主要摘录了《 Effective Objective-C》里的编写高质量的方法;
将引入头文件的时机尽量延后,只在确有需要时才引入,这样就可以减少类的使用者所需要引入的头文件的数量:
class-continuation
分类中。如果不行,则把协议单独放在一个头文件中,然后将其引入;
有时候在编写头文件时,需要引入某个类A(如作为当前类的某个属性来使用),但是不需要知道这个类A的实现细节,此时我们不需要直接引入这个类A的头文件,只需要告诉编译器,类A 是一个类就可以了,然后在实现文件里再引入类A的头文件;向前声明的语法为: @class 类A
;
nil
,则会抛出异常。因此,需要确保值里不含 nil
;如 :
NSNumber *someNumber = [NSNumber numberWithInt:1];
// 字面量语法
NSNumber *someNumber = @1;
NSDictionary *personData = [NSDictionarydictionaryWithObjectsAndKeys:
@"Matt",@"firstName",@"Ga",@"lastName",nil];
// 字面量语法
NSDictionary *persionData= @{@"firstName" : @"Matt",@"lastName" : @"Ga"};
NSString *lastName = [personData objectForKey:@"lastName"];
// 字面量语法
NSString *lastName = personData[@"lastName"];
由以上几个例子中,可以很明显可以看到字面量语法全更加简洁直观;但字面量语法有个小限制,就是除了字符串以外,所创建出来的对象必须属于 Foundation
框架;
static const
来定义“只在编译单元可见的常量”,这类常量一举地在全局符号表里出现;extern
来声明全局常量,并在相关实现文件中定义其值。这类常量会出现在全局符号表里,所以其名称应加以区分,通常使用类名做前缀;全名法则:若常量仅在编译单元内可见,则在前面加字母 k
,如果在类外可见,则通常以类名为前缀;
NS_ENUM
和 NS_OPTIONS
宏来定义枚举类型,并指明其底层的数据类型;switch
语句中不要实现 default
分支,这样的话,加入新枚举类型后,编译器就会提示 switch
语句并没有处理所有的枚举;@property
语法来定义对象中所封装的数据;nonatomic
特质,则不使用同步锁,否则它就是原子的;isEqual:
和 hash
方法;hash
方法时,应该使用计算速度快而且哈希码碰撞机率低的算法;==
操作符比较的是两个指针本身,而不是其所指对象,一般常用 isEqual
方法来判断两个对象的等同性;
invoke a message
),也就相当于在该对象上“调用方法”;在OC中,如果向对象传递消息,那就会使用动态绑定机制来决定需要调用的方法。而在底层,所有方法都是普通的C语言函数,然而对象在接收到消息后,究竟该调用哪个方法则完全于运行期决定。如:
//以下语句是给对象发送一条消息
int value = [someObject messageName :parameter];
其中, someObject
叫接收者, messageName
叫选择子( selector
),选择子和参数合起来称为消息;
Class
对象的指针,用以表明其类型,而这些Class 对象则构成了类的继承体系;isMemberOfClass
能够判断出对象是否为某个特定类的实例;isKindOfClass
能够判断出对象是否为某类或其派生类的实例;
OC 没有其他语言那种内置的命名空间机制。因此我们在起名时需要设法避免潜在的例句冲突。我们在选择前缀时,应该是三个字母的;
全能初始化方法类似于 Java 中提供不同构造参数的构造方法,所有的构造方法最终都会调用其中参数最完整的构造方法;
description
方法类似于 Java
里 Object
的 toString
方法的功能,而且在调试时,如果有实现 debugDescription
方法,则会调用该方法来输出更详细的信息;
class-continuation
分类中将其由 readonly
属性扩展为 readwrite
属性;collection
作为属性公开,而应提供相关方法,以此修改对象中的可变 collection
;
NSError
对象里,经由“输出参数”返回给调用者;如果出现非致命的错误时,则可以令方法返回 nil/0
或使用 NSError
来表明其中有错误发生;
NSCopying
;NSCopying
和 NSMutableCopying
协议;一般情况下,遵从了 NSCopying
协议的对象,执行的都是浅拷贝,除非该对象有特别说明它是用深拷贝来实现 Copying
,否则应该自己去编写深拷贝的;
data source protocal
OC 中广泛使用 delegate pattern
的模式来实现对象间的通信,该模式的主旨是:定义一套接口,某对象若想接受另一对象的委托,则需遵从此接口;其实这就是 Java
里的编程规则里的面向接口编程;所谓的位段结构体,就是用一个属性来表明委托对象实现了哪些协议方法,每个协议方法对应于该属性的一个二进制位;需要注意的是 委托对象与被委托的对象之间的关系应该是非拥有关系,也就是对应的属性得用 weak
来修饰;
Private
的分类中,以隐藏实现细节;
分类机制通常用于向无源码的既有类中新增功能,分类中的方法是直接添加在类里面的;
如:
//给NSString 添加一个分类:ABC_HTTP
@interface NSString(ABC_HTTP)
- (NSString *) abc_urlEncodeString;
@end
class-continuation
分类之外的其他分类中,可以定义存取方法,但尽量不要定义属性;正确的做法是把所有属性都定义在主接口里,类所封装的全部数据都应该定义在主接口里;
class-continuation
分类 隐藏实现细节class-continuation
分类向类中新增实例变量;class-continuation
分类中将其扩展为:可读写;class-continuation
分类里面;class-continuation
分类里声明;例子:
// EOCPerson.h
@interface EOCPerson :NSObject {
.....
}
//EOCPerson.m
//这是EOCPerson的`class-continuation`分类
@interface EOCPerson(){
.....
}
@implementation EOCPerson {
...
}
### 4.6 通过协议提供匿名对象
- 协议可在某种程度上提供匿名类型,具体的对象类型可以淡化成遵从某协议的 id 类型,协议里规定了对象所应实现的方法;
- 使用匿名对象来隐藏类型名称;
- 如果具体类型不重要,重要的是对象能够响应特定方法,那么可使用匿名对象来表示;
OC 里的协议 就是 Java 里的接口,协议定义了一系列方法,遵从些协议的对象实现它们
Objective-C
对象的内存;若方法名以下列词语开头,则其返回的对象归调用者所有:
dealloc
方法里,应该做的事情就是释放指向其他对象的引用,并取消原来订阅的“键值观测(KVO)”或 NSNotificationCenter 等通知,不要做其他事情;避免保留环的最佳方式就弱引用,这种引用经常用来表示“非拥有关系”(nonowning relationship)。将属性声明为 unsafe_unretained
即可。
autorelease
消息后,系统将其放入最顶端的池里。@autoreleasepool
这种新式写法能创建出更为轻便的自动释放池;释放对象有两种方式:一种是调用 realease
方法,使其保留计数立即递减;另一种是调用 autorealease
方法,将其加入“自动释放池”中。自动释放池用于存放那些需要在稍后某个时刻释放的对象;
NSZombieEnabled
可开启此功能;isa
指针,令其指向特殊的僵尸类。从而使该对象变为僵尸对象;retainCount
块所占的内存区域是分配在栈中的。这也就是说块只在定义它的那个范围内有效。
typedef
重新定义块类型,可令块变量用起来更加简单;typedef
中的块签名,无须改动其他 typedef
;
handler
块将相关业务逻辑一并声明;handler
块来实现,则可以直接将块与相关对象放在一起;handler
块,那么可以增加一个参数,使调用者可通过此参数来决定应该把块安排在哪个队列执行;synchronization semantic
,这种做法要比使用 @synchronized
块或 NSLock 对象更简单;@performSelector
系统方法Objective-C
API,能实现纯 GCD 所具备的绝大部分功能,而且还能完成一些更为复杂的操作,那些操作若改用 GCD 来实现,则需另外编码;在执行后台任务时,GCD 并不一定是最佳方式,还有一种技术叫 NSOperationQueue
,它虽然与 GCD 不同,但是却与之相关,开发者可以把操作以 NSOperation
子类的形式放在队列中,而这些操作也能够并发执行;使用 NSOperation
和 NSOperationQueue
的好外:
cancel
就可以了;若使用 GCD 则没有办法取消;NsOperation
对象的属性;Dispatch Group
机制,根据系统资源状况来执行任务dispatch group
,可以在并发派发队列里同时执行多项任务,此时 GCD 会根据系统资源来调度这些并发执行的任务;dispatch group
是 GCD 的一项特性,能够把任务分组。调用者可以等待这组任务执行完毕,也可以在提供回调函数之后继续往下执行,这组任务完成时,调用者会得到通知;
diapatch_once
来执行只需要运行一次的线程安全代码disptch_once
来实现;-标记应该声明在 static
或 global
作用域中,这样的话,在把只需执行一次的块传给 dispatch_once
函数时,传进去的标记也是相同的;常用 diapatch_once
来编写线程安全的单例;
dispatch_get_current_queue
dispatch_get_current_queue
函数的行为常常与开发者所预期的不同,此函数已经废弃,只应做为开发调试用;dispatch_get_current_queue
函数用于解决由不可重入代码所引发的死锁,然而能用此函数解决的问题,也能改用“队列待定数据”来解决;
Foundatoin
与 CoreFoundation
,这两个框架提供了构建应用程序所需的许多核心功能;collection
有四种方式。最基本的是 for
循环,其次是 NSEnumerator
遍历法及快速遍历法,最新,最先进的方式则是"块枚举法";collectioin
含有何种对象,则应修改块签名,指出对象的具体类型;NSEnumerator
遍历法NSEnumerator
是个抽象基类,其中只定义了两个方法,供子类来实现:
想遍历数组时,则可以这样来写代码:
NSArray *anArray = .....;
NSEnumerator *enumerator = [anArray objectEnumeator];
id object;
while((object = [enumerator nextObject])!= nil) {
//dosomething with object
}
遍历字典时,也可以使用类似的代码。并且 NSEnumerator
有多种枚举器供选择,如反向遍历等,使用时可以根据需要选择不同的枚举器;
快速遍历其实就是在基本 for
循环的基础上加了个 in
关键字:
for(id object in anArray){}
NSArray
中定义了下面的方法,实现最基本的遍历功能:
-(void)enumeratorObjetsUsingBlock:(void(^)(id object,NSUInteger idx,BOOL *stop))block;
还有其他类似的遍历方法,可以接受各种选项来控制遍历操作
collection
使用无缝桥接Foundation
框架中的 Object-C
对象与 CoreFoundation
框架中的 c 语言数据结构之间来回转换;CoreFoundation
层面创建 collection
时,可以指定许多回调函数,这些函数表示此 collection
应如何处理其元素;无缝桥接就是用来对 Foundation
框架和 CoreFoundation
框架中的等价的类进行转换, 简单的无缝桥接:
NSArray *anArray = ......;
CFArrayRef afarray = (__bridge CFArrayRef)anArray;
关键字 __bridge
告诉 ARC 如何处理转换所涉及的 OC 对象,而反向转换(CoreFoundation 类 转换为等价的 Foundation 类 )则使用关键字 __bridge_transfer
来实现;
NSPurgeableData
与 NSCache
搭配使用,可实现自动清除数据功能;
load
方法,那么系统就用调用它。分类里也可以定义此方法,类的 load 方法要比分类中的先调用,与其他方法不同, load
方法不参与覆写机制;initialize
消息。由于此方法遵从普通的覆写规范,所以通常应该在里面判断当前要初始化的是哪个类;initialize
和 load
方法应实现得精简一点,有助于保持应用程序的响应能力;initialize
方法城初始化;NSTimer
对象会保留其目标,直到计时器本身失效为止,调用 invalidate
方法可令计时器失效;NSTimer
的功能,用“块”来打破保留环,不过,除非 NSTimer
将来在公共接口里提供此功能,否则必须创建分类,将相关实现代码加入其中;本文分享自 stringwu的互联网杂谈 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!