“属性”(property)是Objective-C的一项特性,用于封装对象中的数据。使用属性之后,编译器会自动写出一套存取方法,用以访问给定类型中具有给定名称的变量。该过程由编译器在编译期执行,编辑器看不到这些合成方法的源代码,编译器还要自动向类中添加适当的实例变量,并且在属性名前添加下划线,作为实例变量的名字。
1.常用关键字
@synthesize : 用属性property之后,会生成实例变量,默认情况下是:_firstName,我们可以通过synthesize对实例变量名通过如下方式进行修改:
@ synthesize firstName = _myfirstName;@dynamic : 它可以用于阻止编译器自动合成存取方法和实例变量。
2.属性特质
- 原子性(atomic,nonatomic)
atomic:具备atomic特质的获取方法会通过锁定机制来确保其操作的原子性。如果两个线程读写同一属性,无论何时总能看到有效的属性值。
nonatomic:不加锁,当一个线程在改写属性值时另外一个线程闯入,可能会把尚未修改好的的属性值读取出来,读取到错误的属性值。
一般情况下我们都只是用nonatomic,原因如下:
(1). 在iOS中使用同步锁开销较大,会带来性能问题。
(2). 即使属性设置成原子性的也不能保证“线程安全”,要实现线程安全还需要更深层次的锁定机制才行。 - 读写权限 (readwrite, readonly)
readwrite: 拥有getter/setter方法,若由synthesize实现,编译器会自动生成这两个方法。
readonly:仅拥有getter方法,若由synthesize实现,编译器会自动生获取方法。
3.内存管理语义
- assign: "设置方法"之后执行针对“纯量类型”的简单的赋值操作,如:NSIntager,CGFloat.
- strong:表明该属性定义一种“拥有关系”,为这种属性设置新值时,设置方法会先保留新值,并释放旧值,再把新值设置上去。
- weak :该特质表明属性定义一种“非拥有关系”,为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。
- copy:该设置方法并不保留新值,而是将其“拷贝”(copy),常用于NSString, NSDictionary, NSArray等数据类型来保护其封装性。
原因:当属性类型为NSString* 时,传递给设置方法的新值有可能指向了个NSMutableString类的实例,这个类是NSString的子类,表示一种可以修改其值的字符串,若此时不拷贝字符串,那么设置完属性之后,字符串的值就可能再对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变”的字符串,以确保对象中的字符串值不会无疑将变动。只要实现属性所用的对象是“可变的”,就应该在设置属性值时拷贝一份。
4.方法名
getter=<name> :指定“获取方法”的方法名,如果某属性是Boolean型时,想在获取方法前加一个“is”前缀,就可以通过该方法来指定。如:
@property (nonatomic, getter = isOn) Bool on;
案例说明
-
weak与strong的区别
//copy,复制一份,相当于retain,retainCount加1 @property (nonatomic, copy) NSString *string1; //weak,与assign类似,retainCount不加1 //指针指向的地址被释放时,指针将被赋值为nil,有效的防止野指针。 @property (nonatomic, weak) NSString *string2; //string1指向值为“string 1”的对象,retainCount=1 self.string1 = [[NSString alloc] initWithUTF8String:"string 1"]; //string2也指向值为“string 1”的对象,但是是若引用,retainCount不变 self.string2 = self.string1; //将string1 指向nil, string1指向的地址被销毁,值为“string 1”的对象的 retainCount=0, self.string1 = nil; //weak型的string2的指针也将被赋值为nil NSLog(@"String 2 = %@---%p", self.string2,self.string2); //打印结果:2016-07-05 13:55:27.400 Test[1328:34343] String 2 = (null)---0x0
如果将上面string2的特性weak更改成strong或者copy,string2将不会指向nil,打印的结果如下:
2016-07-05 14:13:57.352 Test[1391:43333] String 2 = string 1---0x79ff0d30
- copy与strong的区别
从上面看出copy和strong都能实现一种“拥有关系”,也就是使retainCount 加1,为什么一般情况下我们都是将NSString,NSArray,NSDictionary等属性设置为copy,而不是strong呢?
那是因为,NSString,NSArray,NSDictionary等类,都有对应的可变类型,如NSMutableString,NSMutableArray,NSMutableDictionary。NSMutableString这个类是NSString类的子类,表示一种可以修改其值的字符串,若此时不拷贝字符串,那么设置完属性之后,字符串的值就可能再对象不知情的情况下遭人更改。
案例如下:
@property (nonatomic, copy) NSString *string1;
@property (nonatomic, strong) NSString *string3;
@property (nonatomic, weak) NSString *string2;
NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
self.string1 = mStr;
self.string2 = mStr;
self.string3 = mStr;
[mStr appendString:@"de"];
NSLog(@"mStr:%@---%p---%p", mStr,mStr,&mStr);
NSLog(@"copyStr:%@---%p---%p", self.string1,self.string1, &_string1);
NSLog(@"strongStr:%@---%p---%p", self.string3,self.string3, &_string3);
NSLog(@"weakStr:%@---%p---%p", self.string2,self.string2, &_string2);
打印的结果如下:
2016-07-05 14:23:32.886 Test[1458:51397] mStr:abcde---0x7a67eaf0---0xbff2201c
2016-07-05 14:23:32.886 Test[1458:51397] copyStr:abc---0x7a67e410---0x7b06587c
2016-07-05 14:23:32.886 Test[1458:51397] weakStr:abcde---0x7a67eaf0---0x7b065880
2016-07-05 14:23:32.886 Test[1458:51397] strongStr:abcde---0x7a67eaf0---0x7b065884
由上面的打印结果可以看出:
1、设置特性为copy的string1,在执行[mStr appendString:@"de"];后没有被修改,而设置为strong,weak的属性都遭到修改。
2、strong对应的*string3、weak对应的*string2指向的指针和*mStr指向的地址相同,说明他们指向的是*mStr相同的地址,他们的区别只存在于计数器是否加1。而copy对应的*string2却是指向不同于*mStr指向的地址,说明它是复制了一份重新开辟的内存,并且retainCount加1。