-property-
一个OC类通常由成员变量和消息构成。对外开放的成员变量,OC对外提供getter/setter消息。
声明property可以让编译器自动生成getter/setter消息。
ARC使得property 属性设置变的简单了:
读写控制:
readwrite:可读可写,会生成getter和setter方法。
readonly:只读,只会生成getter方法,不会生成setter方法。
引用方式:
copy:拷贝,复制一个对象并创建strong关联,引用计数为1 ,原来对象计数不变。
weak:赋值(ARC),比assign多了一个功能,对象释放后把指针置为nil,避免了野指针。
strong:持有(ARC),等同于retain。
线程安全:
nonatomic:非原子操作,不加同步,多线程访问可提高性能,但不是线程安全的。
atomic:原子操作,与nonatomic相反。
对象生命周期管理是面向对象语言永恒的主题。java用GC应对。C++程序员要小心地实现构造、拷贝构造、以及赋值操作三个函数。而OC则用ARC和property及其属性应对(由于历史原因,OC还要考虑前向兼容,因此会有bridge等问题,这里先搁置。)。
只要是对象,有一个问题是绕不开的,就是当对象拷贝和对象赋值发生时,如何处理成员变量。是直接赋值(weak),还是赋值后引用加1(strong),还是拷贝一份(copy)。C++中也有相应概念:浅拷贝(对应weak)和深拷贝(对应copy)
如果是手写setter,实现copy的语义,注意检查是否是“自我赋值”。即只有源和目标不是一个对象时,才做释放(旧对象)和拷贝(新对象)动作。可以想象,如果是“自我赋值”,而又先做了释放动作,会有什么严重后果。这也是C++中实现赋值操作符(operator=)时,需要注意的问题。
而ARC的引入,由于realse动作是禁止的(编译器承包了),上述检查变得不是必须的了。
property和member:
property用来生成setter和getter,供其他类使用。当用点(dot syntax)连接访问类成员时,setter或getter被调用。
如果是用'->'则直接访问该类成员,不唤起setter或getter。而public,protected,private则限定了'->'访问方式是否成立。
显然,property不受上述三个关键字限定。
如果没有synthesize相应的property,则编译器会为property生成一个默认的member,假设有声明:
@property (strong) NSString* s;
如果没有synthesize该property,则对象中将有两个成员:
NSString* s;
NSString* _s;//getter/setter访问的是它
另外,在property的属性中慎用copy,可能会触发运行时错误:Thread 1: signal SIGABRT,这可能是因为copy发生后,原对象和目的对象共同持有相同的成员对象,导致编译器不知到由谁来释放成员对象。将copy改为strong就ok。
因此设计类时,要非常清楚哪些成员是可以共用的,哪些必须拷贝一份,必要时用手写setter来实现。
必要时,用p命令打印对象,确认对象地址是否正确。
-block-
又叫闭包。如果说类是数据加方法,那么闭包就是方法加数据。也就是说,闭包本质上也是一种封装,只不过它的粒度比类小,只有一个方法加上用到的变量。
闭包和类是平等的,也就是说闭包也是一种类型,他可以声明对象,闭包对象可以作为函数的参数(OC中似乎不支持),也可以由函数返回。
来看两个例子:(来自知乎:http://www.zhihu.com/question/30779258)
int main(int arc, const char* argv[]){
int a = 10;
void(^block)() = ^{printf("a=%d", a)};
block();
return 0;
}
注意到block的实现体里可以访问外部变量a。
下面加入了__block关键字,又有什么区别呢?
int main(int arc, const char* argv[]){
__block int a = 10;
void(^block)() = ^{printf("a=%d", a)};
block();
return 0;
}
编译器生成上述2个block时,对外围变量a的处理有什么不同?
除此之外,注意block和所有其他变量一样,有global、stack、heap之分:
//global block:
void (^globalBlock)() = ^{
NSLog(@"This is a global block");
};
//stack block:
if (YES){
^{
NSLog(@"This is a stack block");
};
}
//heap block:
void (^heapBlock)();
if (YES){
heapBlock = [^{
NSLog(@"This is a stack block");
} copy];
}
heapBlock();