objective-c overview(二)

-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();

 

posted @ 2015-11-15 21:26  米开兰基罗  阅读(154)  评论(0编辑  收藏  举报