Objective-C 入门
Object-C 是 C 的超集,它使用运行时来进行动态绑定,所有对象的类型都是在运行时才能确定的,都是以消息传递的机制运作;所有对象都是在heap中allocated的,在stack中allocate对象是不合法的;内存管理在objc中被抽象为以引用计数的方式来进行管理。
最小化在头文件中import的头文件数量,在尽可能的深处引用它;使用提前声明,消除多余的引用,消除互相引用;使用 continuation category 细化类别 来减少 多余的类方法造成的 过多编译量。
-
对于NSArray、NSNumber、NSDictionary的快捷初始化方法,使用literals语法,使代码更加简洁,更加安全,但只能创建immutable的对象,对于mutable的对象需要使用mutableCopy
NSMutableArray *mutable = [@[@1,@2,@3,@4,@5] mutableCopy];
-
选择使用
static const NSIntger durantion = 1;
来代替
#define durantion 1
定义常量,优点在于避免重定义造成的错误、加入global symbol Table能多处使用、更加严格的类型定义
对象,消息与运行机制
-
最好用直接访问的方法来读取成员变量,而用property生成的setter方法来赋值成员变量;
直接赋值更加快速,但会失去了对成员变量制定的property属性的内存控制;并且不会触发对于该成员变量 KVO 监听函数;
初始化函数中,最好对成员变量直接赋值,因为可能在子类中重载的setter方法会做出特殊的过滤处理;当然,如果该成 员变量只声明在此类的父类中,那只能调用setter方法;
如果成员变量是使用lazy initialization 方法,如- (IFObject*)object { if(!_object) { _object = [IFObject new]; } return _object; }
那读取它时需要调用它的getter方法,否则会出错。
-
使用动态绑定对象,使代码更优雅
void (^block)(NSInteger) = objc_getAssociatedObject(alertView, kAlertKey);
用Key获取与该对象关联的对象或block
可以视为Key/Value方式的扩展,需要 #import <objc/runtime.h>
在AlertView中,我们可以在声明每个AlertView后将处理其点击的delegate方法写为block,与该alertView绑定,这样能 够避免同个类文件声明多个AlertView后委托方法的臃肿不堪
同理,可应用在多个场景中。 使用
[object isKindOfClass:]
检查是否为该类或其子类,使用[object isMemberOfClass:]
检查是否为该类;
对象接口设计
- 在命名类时,多使用三字母前缀(避免与系统二字母前缀冲突)避免命名空间冲突;
引入第三方库时,修改库命名,加入自定义的前缀,以防多次引入第三方库导致的命名空间冲突。 - 一个类必须只有一个指定的初始化方法,其他初始化方法都最终指向它;
在子类中只需要重载指定初始化方法即可; - 定义类的
description
方法,返回描述对象的NSString,使对象能被NSLog输出;
若需要,定义类的dubugDescription
方法,提供更加详细的描述方法; - 偏向immutable对象,防止mutable对象在运行时的修改导致程序异常;
尽可能类头文件只暴露具有readonly属性的property,若在类内部需要修改该成员变量,可使用直接访问,或在class-continuation catalogy里将该property的属性定义为readwrite;
提供一个修改类成员变量的公共方法,而不是将一个可变的成员变量暴露在头文件中; - 在类接口命名上按照Objc的标准进行命名,在命名上表意清晰并完整,向句子一样表述接口作用;
- 在Objc中,没有一个能将类中成员或方法定义为private的方法,偏向用
p_
前缀修饰private变量与方法,以便于公共方法区分开来; - 若是程序发生致命错误,用
NSException
来抛出异常终止程序,在非致命错误上,返回nil或者0,或者返回一个NSError
对象通过委托方法等方式对错误进行处理;
委托与协议
使用delegate委托模型进行对象间的消息传递,优化点为可以使用缓存机制来保存委托对象的消息响应状况(之后再写文章详细描述);
使用
categories
扩展类别技术分割类文件,实现类方法功能的分类,防止单一类文件代码过于冗长;也可以创建一个private
的类别,表示类的私有方法;当自定义或引入
categories
时,尽可能加上自定义的前缀,以免与系统类别定义冲突;-
无法在
categories
类别(除continuation categories
)添加property
,在添加的类别中,property
成员变量是无法进行synthesized
,因此无法为property
提供getter
和setter
方法;解决方法只有自定义property
的访问与修改方法,并加上@dynamic property
来表明
property
的的访问与修改方法在运行时生成; -
在类的实现文件中使用class-continuation categories技术
@interface WYObject() //Property and method @end
这个类别可用于
- 可以添加成员变量与方法到类中,因此可以隐藏无需公开在头文件的成员变量;
- 可以重新声明头文件中声明的
property
,修改其属性,如将readonly
改为readwrite
; - 声明类的私有函数(可以不在类别中声明,但这能增加可读性);
- 能够在类别中声明类遵守的
protocols
协议,若该类不希望公开;
-
使用
protocol
协议来提供一个匿名类@property (nonatomic,weak) id<WYDelegate> delegate
当一个对象的类型需要被隐藏,或者对象实现了什么方法比对象类型更重要时,可以采用匿名类。
内存管理
尽管现在已经是ARC的年代了,但是ARC的本质是系统在程序的适当地方添加上内存管理代码,因此对于内存管理的技术还是需要了解清楚地。
- 程序中,所有对象通过引用关系组成一张内存计数的对象图,在一个对象的声明周期中,对其的retain与release次数必须相等;
- 使用
@autureleasepool
内存池,加在大量动态内存生成的代码中,使内存池立即释放内存,防止内存高峰导致程序crash; - 禁止使用
retainCount
方法,因为在程序的某一刻,retainCount
返回的数值是不能确定的。