首页 > 其他分享 >Objective-C 学习笔记 | 基础

Objective-C 学习笔记 | 基础

时间:2024-06-09 15:03:35浏览次数:23  
标签:对象 笔记 学习 NSDate 实例 Objective now 方法

Objective-C 学习笔记 | 基础

参考书:《Objective-C 编程(第2版)》

第1部分 入门

Objective-C语言是以C语言为基础的,但增加了对面向对象编程的支持。Objective-C语言是用来开发在苹果iOS以及OS X操作系统上运行的应用的编程语言。

第2部分 如何编程

该部分讲解了C语言编程的必要知识,这里只记录Objective-C新增内容。

NSInteger和NSUInteger

NSUInteger是无符号的整型,NSInteger是有符号的整型。

NSInteger是一个封装,它会识别当前操作系统的位数,自动返回最大的类型。
定义的代码类似于下:

#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

这样做让NSInteger和NSUInteger变得通用,不用考虑设备是32位还是64位。

如果使用printf()来输出这两种类型的变量,需要先将NSInteger转换成long,NSUInteger转换成unsigned long。

第3部分 Objective-C与Foundation

该部分开始介绍Objective-C。编写Objective-C程序时,要使用Foundation框架。框架(framework)是由很多类(Class)组成的库。这里记录一些新的知识点。

#import和#include的区别

#include指令告诉编译器做呆板的复制粘贴,将包含的内容粘贴到目标文件中来。而#import指令则让编辑器先检查之前是否导入过这个文件,或是已经被包含到目标文件中了。因此,#import指令导入更快、更有效率。

类与实例、方法与消息

Objective-C也有类和对象的概念,Objective-C的方法和消息与函数类似。如需执行方法中的代码,首先需要发送一条消息给包含这个方法的对象或类。消息发送(指令)必须写在一对方括号中,并且必须包含接收方(receiver)和选择器(selector),如下图所示:

请添加图片描述

date是一个类方法。date方法执行后,NSDate类会在堆上new一个NSDate实例:now,并初始化为当前的日期/时间,然后返回新对象(now)的地址。

请添加图片描述

有了NSDate实例:now之后,我们可以给这个对象发一个实例方法,比如:timeIntervalSince1970。通常来说,实例方法会提供实例中实例变量的信息,或是对实例的实例变量进行操作。

测试程序:

//
//  main.m
//  TimeAfterTime
//
//  Created by 刘文晨 on 2024/6/5.
//

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 向 NSDate 类发送 date 消息,让它执行 date 方法
        NSDate *now = [NSDate date];
        // 打印实例的地址
        NSLog(@"This NSDate object lives at %p", now);
        // %@ 会输出相应对象的“描述信息”
        NSLog(@"The date is %@", now);
        // 实例方法
        double seconds = [now timeIntervalSince1970];
        NSLog(@"It has benen %f seconds since the start of 1970.", seconds);
    }
    return 0;
}

注意:

  1. 类方法和类对应,实例方法和实例对应。receiver和selector不匹配就会出错。
  2. Objective-C是区分大小写的,方法名也是区分大小写的。
  3. Objective-C语言命名习惯为“驼峰式”或“前缀大写的驼峰式”。

alloc和init

消息可以以嵌套的形式连续发送,而唯一必须要以嵌套的形式发送的消息是alloc和init。

每个类都有一个alloc类方法,它创建一个新的对象并返回指向该对象的指针。通过alloc类方法创建出来的对象,必须要经过初始化才能使用。每个类也都有一个init实例方法,它用来初始化实例。

NSDate *now = [[NSDate alloc] init]; // 消息嵌套,和下面的效果一样
NSDate *now = [NSDate date]; // date 方法代码最少,称之为便利方法

nil

nil就是空指针,不指向任何对象。

在Objective-C中,可以向nil发送消息,是合法的,但得到的返回值没有意义。

注意,如果程序向某个对象发送了消息,但不符合预期,应该检查receiver是否为nil。

id

id 类型的含义是:可以指向任意类型的Objective-C对象的指针。‘

id delegate; // id 已经隐含了 * 的作用

类似于 auto(?)

ARC

ARC(automatic reference counting,自动引用计数)为Objective-C提供了一种自动销毁不被引用的对象的机制。当项目开启了ARC,编译器会自动给项目添加代码来计算每个对象的引用数,即每个对象都会对指向自己的指针计数。当引用数为0时, 程序会自动销毁该对象,释放内存。

类似于 shared_ptr。

在Objective-C加入ARC之前,程序员必须手动维护引用计数。

[anObject release]; // abOject 会失去一个拥有方
[anObject retain]; // abOject 会得到一个拥有方
[anObject autorelease]; // abOject 会在 autorelease 池(对象)被排干(drain)的时候收到 release 消息

虽然 ARC 会自动使用 autorelease 池,但是必须由程序创建并排空相应的 autoreleasepool 池,语法如下:

// 创建 autorelease 池(对象)
@autoreleasepool {
  ...
} // autorelease 池被排空

字面量语法

格式:

NSString *lament = @"Hello World!";
NSArray *dataList = @[now, tomorrow, yesterday]; // 这三个都是 NSDate 对象

字面量语法是Objective-C语言的一种缩写,可以以不明确发送消息的方式创建实例。

还没有字面量语法的时候,只能使用 arrayWithObjects: 类方法来创建NSArray实例:

NSArray *dataList = [NSDate arrayWithObjects:now, tomorrow, yesterday, nil]; // nil 是结束标记,让方法停止运行

self

Objective-C的方法都包含一个隐含的局部变量 self。self 是指针,指向运行当前方法的对象。当某个对象要向自己发送消息时,就需要使用 self。它有 2 个简单的用法:

  1. 调用自身的存取方法,避免直接存取实例变量。
  2. 将 self 作为实参传给其他方法,以便其访问“当前的”对象。

NSObject 协议中的 self:

#include <objc/objc.h>
#include <objc/NSObjCRuntime.h>

@class NSString, NSMethodSignature, NSInvocation;
@protocol NSObject

- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
......
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'anObject.dynamicType' instead");
- (instancetype)self;
......
@end

self最终返回的结果就是instancetype类型的代理方法,它是动态类型,最终运行时才会确定,实例方法返回实例类型、静态方法返回的是Class。

super

super 的作用:直接调用父类中的某个方法,或者说从父类开始查找与之匹配的实现。

使用场合:子类重写父类的方法时想保留父类的一些行为。

结构体 objc_super 的官方解释:The compiler generates an objc_super data structure when it encounters the super keyword as the receiver of a message. It specifies the class definition of the particular superclass that should be messaged.

#include <objc/objc.h>
#include <objc/runtime.h>

#pragma GCC system_header

#ifndef OBJC_SUPER
#define OBJC_SUPER

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;
    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    __unsafe_unretained Class class;
#else
    __unsafe_unretained Class super_class;
#endif
};

当遇到super关键字时,编译器会生成一个objc_super结构体,作为消息的接收者,objc_super结构体使得接收消息的父类的定义被明确化。

isa指针

任何一个对象的isa指针都会指向创建该对象的类。

给对象发送消息的时候,对象就会通过isa指针找到该对象的类并查询是否有该消息名的方法。如果没有,就会继续查询它的父类,直到找到名为消息名的方法,或者到达继承链的顶端(NSObject)为止。

description方法和%@转换说明

格式说明符%@让对象描述自己,实际上在处理%@时,程序会向相应的指针变量所指的对象发送 description 消息。

description 方法会返回一个描述类实例的字符串。description 是一个 NSObject 方法,所以所有的对象都有这个方法。默认的 NSObject 实现会以字符串的形式返回该对象在内存的地址。不同的类可以重写(override)description 方法,来最有效地描述实例。

强引用循环和弱引用

两个对象互相拥有的关系将导致相关对象都无法释放,这种情况叫强引用循环,这是导致内存泄露的常见原因。

请添加图片描述

Xcode的Instruments中的Leaks组件可以找出程序中的强引用循环:

请添加图片描述

通过弱引用,可以解决该问题。弱引用是不说明所有权的指针,把 BNRAsset 的 holder 属性改成 weak,就能让 BNRAsset 对象不拥有它的 holder(BNREmployee 对象)。代码如下:

#import <Foundation/Foundation.h>
@class BNREmployee;

NS_ASSUME_NONNULL_BEGIN

@interface BNRAsset : NSObject

@property (nonatomic, copy) NSString *label;
@property (nonatomic, weak) BNREmployee *holder;
@property (nonatomic) unsigned int resaleValue;

@end

NS_ASSUME_NONNULL_END

完整程序见于:UestcXiye/Objective-C-Practice

弱引用的自动置零特性:强引用会保留对象的拥有方,使其不被释放。而弱引用则不会保留,因此标为弱引用的实例变量与属性指向的对象可能会消失,如果发生了这种情况,那么这个实例变量或属性会被设为 nil。

Collection 类

Collection 类的实例用于保存指向其他对象的指针。主要分为三种:

  1. NSArray 及其子类 NSMutableArray
  2. NSSet/NSMutableSet
  3. NSDictionary/NSMutableDictionary

注意以下 4 点:

  1. Collection 对象只能保存对象的指针,不能保存基本类型变量或指向结构的指针,需要先将这些 C 语言基本类型封装成对象,再存入 Collection 对象。

    例如:float变量、int变量等要先转换成NSNumber再存入Collection对象,或者直接用NSNumber字面量实例。结构可以用NSValue(它是NSNumber的父类)实例来封装。

  2. 其中 NSArray、NSSet、NSDictionary 具有不可修改性。使用它们可以节约内存提高性能,因为它们的 copy 方法仅仅返回指向自己的指针,不会做拷贝之类的事情。

  3. 向可改变的 Collection 对象中加入某个对象时,Collection 对象会成为该对象的拥有方;同理,移除对象时,Collection 对象就不再是该对象的拥有方了。对于不可改变的 Collection 对象而言,创建时就拥有其中所有对象的所有权,而 Collection 对象被释放时,它就放弃其中所有对象的所有权。

  4. Collection 对象不能保存 nil,需要将“空”包装成一个对象,可以使用 NSNull 类。

标签:对象,笔记,学习,NSDate,实例,Objective,now,方法
From: https://blog.csdn.net/ProgramNovice/article/details/139551049

相关文章

  • 一起学习javascript-进阶版函数(1)
    <script>  //举个例子 functionsum(x){    returnx+1;  }    functionadd(a,b,f){    varc=f(a)+f(b)    console.log("c的值为:"+c);  }  //给add函数传参  add(3,6,sum);// 这里的f相当于为//......
  • 一起学习javascript-函数(2)
    <script>  //变量作用域与解构赋值  functionf1(y){  varx=1;  x=x+2;  console.log(x+y);  console.log(x);  //因为变量x在函数f1中申明,在这里属于局部变量,所以x只能在f1中访问,f1执行完,x就销毁了}f1(2);//为了更直观一点,调用......
  • HarmonyOS ArkTS组件 | Flex 以弹性方式布局子组件的容器组件 学习记录
    HarmonyOSArkTS组件|Flex以弹性方式布局子组件的容器组件学习记录前言:最近需要用到弹性布局,记录一下。(忽略图片水印QAQ)说明:Flex组件在渲染时存在二次布局过程,因此在对性能有严格要求的场景下建议使用Column、Row代替。Flex组件主轴默认不设置时撑满父容器,Column、Row组......
  • [无监督学习] 14.详细图解k-means 算法
    k-means算法把相似的数据汇总为簇的方法叫作聚类。k-means算法是一种聚类算法,该算法非常简单,所以被广泛应用于数据分析。概述k-means算法是一种有代表性的聚类算法。由于该算法简单易懂,又可以用于比较大的数据集,所以在市场分析和计算机视觉等领域得到了广泛的应用。我......
  • CUDA编程学习笔记-02
    CUDA代码高效计算策略高效公式✒️Math代表数学计算量,Memory代表每个线程的内存......
  • 【机器学习】与【数据挖掘】技术下【C++】驱动的【嵌入式】智能系统优化
    目录一、嵌入式系统简介二、C++在嵌入式系统中的优势三、机器学习在嵌入式系统中的挑战四、C++实现机器学习模型的基本步骤五、实例分析:使用C++在嵌入式系统中实现手写数字识别1.数据准备2.模型训练与压缩3.模型部署六、优化与分析1.模型优化模型量化模型剪枝......
  • FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
    ​XviD是个开源的视频编解码器,它与DivX一同被纳入MPEG-4规范第二部分的视频标准,但DivX并未开源。早期的MP4视频大多采用XviD或者DivX编码,当时的视频格式被称作MPEG-4。现在常见的H.264后来才增补到MPEG-4规范的第十部分,当然如今使用XviD压缩的视频已经不多了。在《FFmpeg开发实战......
  • 跟着GPT学习Java线程中断机制
    Java中的线程中断是一个复杂但非常重要的概念,它允许一个线程告知另一个线程希望它停止正在做的事情。这个机制是协作式的,意味着被请求中断的线程需要自己检查中断状态,并且决定如何响应中断请求。下面我将系统地讲解Java中的线程中断知识点。 1.中断标志每个线程都有一个内部......
  • OpenCompass大模型测评实战学习笔记
    一、OpenCompass介绍:评测相关:评测意义:研究评测对于我们全面了解大型语言模型的优势和限制至关重要;研究评测有助于指导和改进人类与大型语言模型之间的协同交互;研究评测可以帮助我们更好地规划大型语言模型未来的发展;评测能了解不同语言模型之间的性能、舒适性和安全性,能够帮......
  • 程序员学习Processing和TouchDesigner视觉编程相关工具
     ProessingProcessing是一种用于视觉艺术和创意编程的开发环境和编程语言。它最初是为了帮助非专业程序员学习编程,特别是那些对于创意编程和视觉表达感兴趣的人。Processing提供了简单易用的API,使得绘制图形、创建动画和交互式应用变得相对容易。在前端应用Processing......