Table of Content

iOS 的各种接口见识完之后,又想回炉了,想多了解下底层的一些东西,刚好最近在学 Swift,他俩比较像,索性一锅端了。

@property (nonatomic, copy) NSString *recievedContent;

以前定义字符串这么写,只记得用 nonatomic 和 copy 就能定义字符串,虽说 copy 的作用略知一二,但为啥这么写还是不清楚。还是基础不够扎实。

这次要说的内容是 Objective-C 中的 @property和 @synthesize。在这之前先讲讲访问器(Accessor),也就是我们所知道的 setter 和 getter 方法。访问器是很重要的技术,用来访问和设置对象的实例变量(不是指对象本身,而是对象中的属性)。有时候可能需要用不同的方式或者通过计算等方式来获取或设置实例变量,访问器给了我们很大的灵活性。在 Cocoa 中访问器有很多的优点:

  • 实现灵活性。 可以在访问器中改变并实现不同的实例变量访问方式而不影响其他代码。
  • 可维护性。通过访问器对实例变量的更改易于维护。
  • 支持 KVC 和 KVO。 KVC 和 KVO 是很强大的技术。但是它们依赖于正确命名访问器。

下面这段代码简单的实现了一个访问器(setter 和 getter):

{
	NSString *_recievedContent;
}

//setter
-(void)setRecievedContent:(NSString *)recievedContent {
     _recievedContent = recievedContent;
}

//getter
-(NSString *)recievedContent {
     return recievedContent;
}

这么写的确很麻烦,有没有更好的一种方法呢?当然有啊,用 @property!

@property (nonatomic, copy) NSString *recievedContent;

这么写跟上面那几行等效的,那么问题又来了,nanotomic 和 copy 是做啥的。

这些关键字都是有用的,大致分为三类:

原子性

  • atomic(默认):atomic 意为操作是原子的,意味着只有一个线程访问实例变量。atomic 是线程安全的至少在当前的访器上我是安全的。它是一个默认的,但是很少使用。它的比较慢,这跟 ARM 平台和内部锁机制有关。

  • nonatomic:跟 atomic 刚好相反。表示非原子的,可以被多个线程访问。它的速度比atomic快。但不能保证在多线程环境下的安全性,在单线程和明确只有一个线程访问的情况下广泛使用。

访问器控制

  • readwrite(默认):readwrite 是默认的,表示同时拥有 setter 和 getter。

  • readonly:readonly 表示只有 getter 没有 setter。

内存管理

  • retain:使用了 retain 意味着实例变量要获取传入参数的所有权。具体表现在 setter 中对实例变量先 release 然后将参数 retain 之后传给它。

  • assign(默认):用于值类型,如 int, float, double 和 NSInteger, CGFloat 等表示单纯的复制。还包括不存在所有权关系的对象,比如常见的 delegate。

  • strong:是在 ARC 伴随 iOS 引入的时候引入的关键字是 retain 的一个可选的替代。表示实例变量对传入的参数要有所有权关系即强引用。strong 跟 retain 的意思相同并产生相同的代码,但是语意上更好更能体现对象的关系。

  • weak: weak 跟 assign 的效果相似,不同的是 weak 在对象被回收之后自动设置为 nil。而且 weak 只能用在 iOS5 或以后的版本,对于之前的版本,使用 unsafe_unretained。

  • unsafe_unretained:weak 的低版本替代。

  • copy:copy 是为是实例变量保留一个自己的副本。

现在知道 @property 的用法了,再回过头说 @synthesize

Xcode4.4 之前,还需要写这么一句:

@synthesize recievedContent = _recievedContent;

@synthesize 作用就是生成 setter 和 getter 方法。不过在之后的版本中,如果什么都不写,默认就是 @syntheszie var = _var;,目的就是生成 setter 和 getter 方法。

当然了,也可以手动写成 @syntheszie recievedContent,或者 @syntheszie recievedContent = anythingElse,就可以通过指针的方式用 recievedContent,或者 anythingElse 直接调用变量,而不是 self.recievedContent

和这个类似的,还有一个 @dynamic 关键字,代表用户要自己实现 setter 和 getter 方法。如果你不写,编译的时候倒是能通过,运行的时候,就会 Crash。