文章目录
  1. 1. @property
    1. 1.1. 线程安全
      1. 1.1.1. atomic、nonatomic
      2. 1.1.2. readonly、readwrite
    2. 1.2. 内存管理
      1. 1.2.1. assign
      2. 1.2.2. weak(ARC)
      3. 1.2.3. copy
      4. 1.2.4. Copy扩展
        1. 1.2.4.1. 前提
        2. 1.2.4.2. 作用
        3. 1.2.4.3. 浅复制和深复制
        4. 1.2.4.4. @property和copy
        5. 1.2.4.5. 自定义对象
        6. 1.2.4.6. 特别注意
      5. 1.2.5. strong(ARC)、retain(MRC)
    3. 1.3. @synthesize和@dynamic
      1. 1.3.1. @synthesize
      2. 1.3.2. @dynamic
  2. 2. 参考链接

@property

在普通的OC对象中,@property就是编译器自动帮我们生成一个私有的成员变量和getter、setter方法的声明及实现。为了研究编译器是如何实现@property的,我们需要使用clang。clang提供一个命令,可以将OC的源码改写成c++的,借此可以研究@property具体的源码实现方式。该命令是:

1
clang -rewrite-objc xxx.m

除此之外我们还可以通过苹果开源的runtime进行研究,源码地址。源码

线程安全

atomic、nonatomic

atomic为原子性,会对set方法的实现进行加锁,多线程下可以一个线程写多个线程读,主要用在mac开发;nonatomic为非原子性,set方法的实现不加锁(比atomic性能高)。因为mac开发早于iOS开发,所以默认值为atomic。(A joke!)在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备nonatomic特质,则不使用同步锁。

一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全” ( thread safety),若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如,一个线程在连续多次读取某属性值的过程中有别的线程在同时改写该值,那么即便将属性声明为atomic,也还是会读到不同的属性值。因此,在iOS开发中,你会发现,几乎所有属性都声明为nonatomic;但是在开发Mac OS X程序时,使用 atomic属性通常都不会有性能瓶颈。

问题来了:

@property (strong) NSMutableArray *array; 有什么问题?

线程安全特性默认为atomic,该属性使用了同步锁,会在创建属性时生成一些额外的代码用于帮助写多线程程序,这会带来性能问题,通过显示声明nonatomic可以节省这些虽然很小但是不必要的额外开销。

##访问权限

readonly、readwrite

readonly只生成get方法的声明和实现; readwrite同时生成get方法和set方法的声明和实现。

内存管理

每个对象都有一个引用计数器,每个新对象的计数器默认是1,当对象的计数器减为0时就会被销毁;通过retain可以让对象的计数器加1、release可以让对象的计数器减1,还可以通过 autorelease pool 管理内存;只要调用了alloc、copy、new、retain方法产生的新对象,都必须在最后调用一次release或者autorelease;如果使用ARC,编译器会自动生成管理内存的代码。

assign

set方法的实现是直接赋值,用于基本数据类型的简单赋值操作,用于非OC对象。

weak(ARC)

weak表明该属性定义了一种“非拥有关系(nonowning relationship)”,set方法的实现既不release旧也不retain新值,同assign类似,然而当对象销毁的时候,指针会被自动设置为nil,weak必须用于OC对象。

使用场合:

*在ARC中,出现循环引用的时候,必须要有一端使用weak,比如:delegate。

*自身已经对它进行一次强引用,没有必要在强引用一次,此时也会使用weak,比如@IBOutlet。

copy

set方法的实现是release旧值,copy新值,用于NSString、block等类型。
栗子来了:

1
2
@property(nonatomic, copy) NSString *name;
- (void)setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name copy]; } }

字符串使用copy是为了外部把字符串内容改了不影响该属性;block使用copy是在MRC遗留下来的,在MRC中方法内部的block是在栈区的,使用copy可以把它放到堆区。在ARC中对于block使用copy还是strong效果是一样的。

Copy扩展

前提

实现NSCopying或NSMutableCoping。

作用

  1. 改变原对象不影响拷贝对象。
  2. 改变拷贝对象不影响源对象。

浅复制和深复制

Copy产生的是不可变副本,MutableCopy产生的是可变副本。

只要源对象是不可变类型且产生的对象也是不可变类型的时的情况是浅复制,其他情况都是深复制。浅复制是源对象和拷贝对象指向同一对象,深复制是产生了不同的对象。

@property和copy

在set方法中release旧值copy新值,用于NSString和block,可以保证属性不会被外部变量(例如NSMutableString类型变量)的改变所影响。

问题来了:

@property (nonatomic,copy) NSMutableArray *array;这个写法会出什么问题?

copy产生的是不可变副本,在set方法中release旧值copy新值,所以运行时类型为NSArray,编译时类型为NSMutableArray,所以对array执行添加、删除、修改数组内的元素的时候程序会因为找不到对应的方法而崩溃。

栗子来了:

当一个使用 initWithArray: 初始化方法创建的NSMutable对象赋值给array属性,那么之后array执行可变数组的方法,比如:removeObjectAtIndex: 时会出现”-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x100206cd0”的崩溃。原因在于array属性在被赋值(setter)的时候默认执行了copy方法后变为了不可变NSArray对象。

自定义对象

  1. 遵守NSCopying或NSMutableCopying协议。其实也可以在代码中不写协议类的遵守,只实现里面的方法,协议只是用来方便生成快捷方法的。
  2. 实现copyWithZone或mutableCopyWithZone。即用self实例化对象([[[self class] allocWithZone: zone]init];)、属性赋值、返回对象。

特别注意

编译时类型和运行时类型,应以运行时类型为准。

strong(ARC)、retain(MRC)

set方法的实现是release旧值,retain新值,用于OC对象类型。

栗子来了:

1
2
@property(nonatomic, copy) NSString *name;
- (void)setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name retain]; } }

##指定方法名称
setter=

getter=

@synthesize和@dynamic

@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是:

1
@synthesize var=_var;

@synthesize

@synthesize的语义就是,如果没有指定成员变量的名称会自动生成一个属性同名的成员变量,如果这个成员变量已经存在了就不再生成。

如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。

在@property被增强之后其实已经很少使用@synthesize

@dynamic

@dynamic告诉编译器,属性的setter方法和getter方法由我自己实现不用自动生成(对于readonly的属性只需提供getter方法即可),如果你木有提供setter方法和getter方法,编译时是没问题,但是当程序运行时调用会由于缺少setter方法或gettr方法导致程序崩溃。

编译时是靠Xcode把关,运行时靠runtiime机制来执行相应的方法,这就是所谓的动态绑定。

参考链接

iOS面试题

iOS面试题集锦

《招聘一个靠谱的iOS》面试题参考答案(上)

文章目录
  1. 1. @property
    1. 1.1. 线程安全
      1. 1.1.1. atomic、nonatomic
      2. 1.1.2. readonly、readwrite
    2. 1.2. 内存管理
      1. 1.2.1. assign
      2. 1.2.2. weak(ARC)
      3. 1.2.3. copy
      4. 1.2.4. Copy扩展
        1. 1.2.4.1. 前提
        2. 1.2.4.2. 作用
        3. 1.2.4.3. 浅复制和深复制
        4. 1.2.4.4. @property和copy
        5. 1.2.4.5. 自定义对象
        6. 1.2.4.6. 特别注意
      5. 1.2.5. strong(ARC)、retain(MRC)
    3. 1.3. @synthesize和@dynamic
      1. 1.3.1. @synthesize
      2. 1.3.2. @dynamic
  2. 2. 参考链接