3.1 命名约定
良好的命名,Cocoa 命名约定比较注重清晰性。这一点与C++大相径庭。
1)方法名要能够清晰地反应出参数类型和返回类型。
//令人困惑
- (void) add;
//从上面的名称看来,add方法需要接受一个参数,但实际上它不接受任何参数。难道这个方法是在某个默认对象上做add吗?
//下面这种做法就清晰多了
- (void)addEmptyRecord;
- (void) addRecord:(Record *)record;
//不正确,从名称上看setURL应该接受一个URL最为参数对象而不是NSString
- (void) setURL:(NSString *) URL;
//正确
- (void) setURLString:(NSString *) string;
- (void) setURL:(NSURL *) URL;
2) 静态变量以 s 开头
static MYThing *sSharedInstance;
3)全局变量以 g 开头,通常情况下应该避免使用常量之外的全局变量
MYThing * gGlobal;
4)常量在 Cocoa 和 Core Fondation 中使用不同的命名方式。在Core Fondation 中,常量以 k 开头,在 Cocoa 中则不是。建议文件作用域内的(静态)常量都以 k 开头。
static const NSUInteger kMaximunNumberOfRows = 3;
5)方法参数名称通常要加一个冠词(a,an,the)作为前缀。“the” 用的比较少,只在特制某些非常重要的或者唯一的对象使用。用这种方式对参数进行命名,可以避免它们与方法中的局部变量和实例变量混淆。特别有帮助的一点是,避免无意地修改它们。
6)实例变量以下划线开头。
7)类名应该总是以大写字母开头,方法名和变量名则应该以小写字母开头。所有的类名和方法名都必须使用驼峰式大小写来分割单词。
3.2 自动引用计数ARC(Automatic Reference Counting)
ARC 极大的减少了 Cocoa 开发中的常见编程错误:retain 跟 release 不匹配。ARC 并不会消除对 retain 和 release 的调用,而是把这项原本属于程序员的工作交给了编译器。记住,ARC 并不等同于 垃圾回收。它只是在编译的时候自动在合适的位置插入一些代码。垃圾回收机制是在运行时起作用,会影响运行时效率,而ARC 是在编译的时候插入内存管理代码,不影响运行时效率,所以内存回收比垃圾回收的效率要高,能提升系统性能。
ARC 不是垃圾回收,尤其他不能像 Snow Leopard 中的垃圾回收机制那样处理循环引用(保留)。下图中的对象 A 与对象 B 之间存在循环保留。
在Snow leapard 的垃圾回收机制下,如果从“外部对象”到“对象A” 的引用链接中断了,对象A 和 对象B 都会被销毁,因为它们从程序中孤立出去了。而在ARC 中,对象A 和 对象B 都不会被销毁,因为它们的引用计数都大于0。因此,在IOS开发中,必须要做好对强引用的跟踪管理以避免出现循环引用。
属性关系有两种主要类型:strong 和 weak,相当于非 ARC 中的 retain 和 assign。只要存在一个强引用,对象会一直存在,不会被销毁。(这里可以先简单地理解为 强引用 是存在retainCount加一,而弱引用则不存在)。
Objective-C 中一直存在循环引用的问题,但在实际应用中很少出现循环引用。大部分的循环引用都是由于 delegate 引起的,所以应该总是把 delegate 属性声明为 weak。当引用的对象被销毁后,weak 引用会被自动设置为nil,与 assign 相比这是一个巨大的进步,因为 assign 可以指向被释放的内存,导致程序崩溃。
在 ARC 之前,合成属性(synthesized property)的默认属性是 assign,而在ARC 中,默认属性则是 strong。这一点要注意下。
3.3 属性
从最近几个版本的IOS 开始,编译器会根据属性自动合成实例变量和相对应的存取方法。通常情况下,已经不需要再使用 @synthesized 关键字了。建议以后在编程中都是用属性和自动合成的实例变量,在头文件中声明共有属性,在 .m 文件中的类扩展部分声明私有变量。如下实例:
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, readwrite, weak) id delegate;
@property (nonatomic, readonly, strong) NSString *readonlyString;
@end
// MyClass.m
@interface MyClass () //私有方法
@property (nonatomic, readwrite, strong) NSString *readonlyString;
@property (nonatomic, readwrite, strong) NSString *privateString;
@end
上面的代码会制动创建几个实例变量:_delegate, _readonlyString,_privateString。注意上面的 readonlyString 在类扩展部分被重新定义使用了 readwrite 关键字进行修饰,这样便为该类创造了一个私有的设置方法(setter)。
另外一种私有实例的方法可以在 @implementation 这一块实现。如下代码:
@implementation Something
{
__weak NSString *_name; //声明一个weak实例变量,默认是strong
}
3.4 存取器
应该使用存取器访问实例变量,避免直接使用实例变量。
3.5 分类和扩展
使用分类(category)可以在运行时向某个现有的类添加新的方法。包括苹果官方的 Cocoa 类在内的任何类,都可以使用分类进行扩展(extension),新加入的方法类在类的所有实例中都可以用。分类用于以模块化的方式将一个大型类分化成多个更易维护的部分。
分类的声明方法如下:
@interface NSMutableString (Capitalize)
- (void) capitalize;
@end
capitalize 就是分类的名称。
注意:
1)这里没有声明任何实例变量,分类中不能声明实例变量,也不能合成属性(不过可以声明属性)。
2)分类不要求方法一定要实现,但是如果没有实现分类的方法,在调用过程中会因为找不到而抛出异常。
分类的实现:
@implementation NSMutableString (Capitalize)
- (void) capitalize
{
[self setString:[self capitalizedString]];
}
@end
3.5.3 类扩展
Objective-C对分类添加了一个有用的功能,叫做类扩展(class extension)。类扩展的声明方法跟分类很像,只有不括号内的名字是空的:
@interface MYObject()
- (void) doSomething;
@end
类扩展是在 .m 中实现私有方法的一个很棒的方式。不同于分类,在类扩展中声明的方法与在类中声明的方法完全一致,这些方法必须实现,且在编译时被添加到类中,而分类是在运行时添加的。在类扩展中也可以声明合成属性。
3.6 正式协议和非正式协议
协议是 Objective-C 中的一个重要部分,在 Objective-C 2.0 中,正式协议已经非常普遍了。但是,在 Objective-C 1.0 的协议方法中没有 @optional 这个标签,所有的协议方法都是必须实现的,这种协议的用处不大。通常我们希望一部分协议是可选的,一部分是必须实现的,而Objective-C 1.0 中是不可能实现的。所以开发者通常会使用“非正式协议”来实现(非正式协议其实就是 NSObject 的一个分类)。
Objective-C 2.0 添加了 @optional 这个标签,是它能够在正式协议中声明可选方法。
使用一个协议很简单,只要在父类后面的尖括号中包含协议的名称就可以了,如下代码:
@interface AppController : NSObject
声明一个协议如下:
@protocol CCDirectorDelegate
//可选的方法
@optional
-(void) updateProjection;
//@required 实现必须要实现的方法
@required
...
@end
通常声明协议后,通常需要一个熟悉以便操作它,通常使用 id
@property (nonatomic,readwrite,weak) id delegate;
呼呼~~~累了,休息先