《精通Objective-C》是19年去字节实习时,伟池推荐的iOS开发入门读物之一。
入门
OC平台
OC开发环境
OC编程语言、OC运行时环境、软件库、软件开发工具OC的优势
面向对象、对象消息传递、动态的运行时系统、内存管理、内部检查和获取信息、支持原生C语言、apple的技术支持
使用类
属性
- 属性定义
显式定义(直接定义getter/setter方法)、通过关键字补全(@synthesize使关键字被自动创建)、自动补全(OC自动把未声明的补全)、动态生成(@dynamic)
对象和消息传递
发送消息
接收消息的对象会在运行时确定调用哪个方法。
消息转发
OC的对象传递,根据接收到的消息,找到并执行对象中的方法。既可以在代码里指定对象的类型,编译时静态绑定,又可以到运行时再解析(动态类型)。
不管什么方法设置对象的类型,如果没有相应方法能够允许这种对象,程序就会抛出异常。OC提供消息转发,使得对象可以把消息发送给能够作出回应的其他接收器。如果没有接收器能够处理,就自己默默吞下消息,不执行也不报错。
快速转发 重写NSObject的forwardingTargetForSelector:方法,把这个方法转发给其他对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17@interface helper : NSObject
- (NSString *) func;
@end
@implementation hd {
@private helper *helper;
}
- (id) forwardingTargetForSelector:(SEL)aSelector {
if ([helper respondsToSelector: aSelector]) {
return helper;
}
return nil;
}
/**
如果给hd发送了一个不能处理的消息,该方法先会检查消息是否可以由目标对象helper处理,如果可以处理,就返回该对象,否则返回nil
*/
@end完整转发 重写NSObject的forwardInvocation:方法。
内存管理
错误的内存管理会引发内存泄漏和悬挂指针。前者指程序没有释放不再使用的对象,浪费内存资源,后者指程序释放了仍在使用的对象,如果将来程序访问了这些对象,就会出现错误。
MRC
基本原则:
- 为创建的所有对象设置所有权
- 使用retain方法获取对象的所有权
- 不再使用某个对象时,要release所有权
- 不能放弃不归你所有的对象的所有权
释放内存:
对象的引用计数为0时,系统会通过dealloc方法释放该对象占用的内存。
通过autorelease方法延迟释放操作:
自动释放池代码块提供了在将来某个时间放弃对象所有权的机制,所以不需要再编写release的相关代码。
ARC
MRC可以精细控制内存使用的情况,代价就是大幅度增加编程人员的负担。
另外,ARC是在编译时确定release和retain的,因此比GC更可靠,不会在运行时暂停。
使用规则:
不能手动编写发送retain、retainCount、release、autorelease和dealloc消息的代码。在ARC下,会自动生成dealloc的方法,释放对象并调用父类的dealloc方法。
不能直接进行id和(void *)类型的强转。因为ARC只能管理对象,而(void *)能够转化为任何指针类型的通用指针。
不能使用内存区NSZone。
不能使用C结构中的对象指针。因为无法判断合适的retain和release。
生命周期限定符:
__strong 表明在作用域内一直保留
__weak 表明对象随时可以释放,只有对象拥有其他强引用时才有作用,当对象被释放时,变量设置为nil
__unsafe_unretained 与weak的区别是不会把变量置为nil
__autoreleasing 通过引用传递对象
避免循环引用:父对象强引用其子对象,子对象弱引用其父对象。
这里遇到的实际例子是delegate
@property(weak) id
预处理器
OC含有一个预处理器,在编译前对源文件进行预处理,其中一些操作是自动执行的,另一些是根据源文件包含的语言元素执行的。
从源文件转换为可执行文件,主要经过以下阶段:
词法分析(预处理器)、语法分析(语法分析器)、AST、生成代码、汇编、链接、可执行的二进制文件
词法分析阶段,把源代码拆分成多个记号,每个关键字、操作符等都会被表示为一个记号。
语法分析阶段,通过记号创建抽象语法树AST,检查表达式合法性。
生成代码和优化阶段,代码功能不变,但体积更小、性能更好。
汇编阶段会把上一阶段生成的代码转换为在目标平台可执行的机器代码。
最后在链接阶段,会把所有代码合并成为一个独立的可执行程序。
预处理器会根据既定的规则,把输入的字符序列进行替换,如果记号序列中有预处理语言元素,会根据这些记号进行替换。
预处理语言主要包括源文件的内容、条件编译和宏展开。
指令
预处理器指令以井号开头,后面紧跟指令名,之后是相应的参数,如:
1 | #import "elements.h" |
头文件包含:include import
条件编译:if、elif、else、endif、ifdef、ifndef
诊断:error、warning、line
pragma
1 | // 1. 使用#import防止递归包含 |
宏
有名称的代码段,可以用来定义常量,也可以配合输入实现函数的功能
1 | #define maxn 1005 |
不要过度使用宏,虽然它们功能强大,但是使用时的危险性也非常大。
预处理器指令在词法分析阶段发挥作用,根据一系列预定的规则,对源文件进行记号替换,执行头文件包含、条件处理、宏展开以及特定平台操作。
专家级技巧:使用ARC
OC程序获取以alloc、new、copy和mutableCopy创建的对象的所有权。
想要释放对象所有权,可以1.重新分配变量 2.将nil赋予变量 3.释放对象的所有者
为了方便开发人员在OC程序中使用C语言的API,苹果提供了直接桥接和ARC桥接转换。
OC 直接桥接
apple基于C语言的CF框架和基于OC的Foundation框架有许多数据类型提供了互用性,这种功能称为直接桥接。比如CFStringRef会被强转为NSString对象。
OC编译器不会自动管理CF的对象的生命周期,所以在ARC下使用CF数据类型,就要手动管理这些对象。
ARC桥接转换:
使用ARC时,通过ARC桥接转换可以直接桥接数据类型。
__bridge 在不改变所有权的情况下,将CF框架数据类型转换为Foundation框架对象。反之亦然。使用这个标记可以使得编译器不报错,并且不会改变对象的所有权。
__bridge_retained 可以将Foundation框架对象转换为CF框架数据类型对象,接管ARC对象的所有权。这样就可以手动管理直接桥接数据的生命周期。
__bridge_transfer 将CF数据类型转成Foundation数据类型,把对象所有权交给ARC管理。
1 | CFStringRef cstr = CFStringCreateWithCString(NULL,"hello world!",kCFStringEncodingASCII); |