Objective-C中的@property和@synthesize用法

Posted Ning静致远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Objective-C中的@property和@synthesize用法相关的知识,希望对你有一定的参考价值。

描述
  • @代表“Objective-C”的标志,证明您正在使用Objective-C语言。
  • 是Objective-C语言关键词。
  • @property与@synthesize配对使用。
  • 功能:让编译器自动编写一个与数据成员同名的方法声明来省去读写方法的声明。
property属性
  • 作用:提供成员变量的访问方法的声明、控制成员变量的访问权限、控制多线程时成员变量的访问环境。  
  • 使用范围:property不但可以在interface,在协议protocol和类别category中也可以使用。
synthesize 合成访问器方法
  • 作用:实现property所声明的方法的定义。其实说直白就像是:property声明了一些成员变量的访问方法,synthesize则定义了由property声明的方法。  
  • 他们之前的对应关系是:property 声明方法 ->头文件中申明getter和setter方法 synthesize定义方法 -> m文件中实现getter和setter方法。  

如:

1、在头文件中:

1. @property int count;  
等效于在头文件中声明2个方法:
1. - (int)count;  
2. -(void)setCount:(int)newCount;  
2、实现文件(.m)中

@synthesize count;  
等效于在实现文件(.m)中实现2个方法。
1. - (int)count  
2. {  
3.     return count;  
4. }  
5. -(void)setCount:(int)newCount  
6. {  
7.     count = newCount;  
8. }  
  • 在Xcode4.5及以后的版本中,可以省略@synthesize,编译器会自动帮你加上get 和 set 方法的实现,并且默认会去访问_age这个成员变量,如果找不到_age这个成员变量,会自动生成一个叫做 _age的私有成员变量。
  • 注意:ios 中setter和getter方法不可以同时写,在.m文件中同时实现getter和setter时候需要@synthesize age = _age.表示要手动生成setter和getter方法,同时用age的地方可以用_age,_age是写在花括号里的字段,而age是@property里声明的属性,字段是私有的,而属性可以供外界访问,私有字段在校验数据合法性等情况(尤其是在安全方面)有着积极作用。

 

例如:@interface MyClass()
@property (nonatomic, copy) NSString *age;
@end
 
@implementation MyClass
@synthesize age = _age ;
- (void)setAge:(NSString *)age
{
    …..
}
- (NSString *)age
{
   ....
}
 
@end
以上等效的函数部分由编译器自动帮开发者填充完成,简化了编码输入工作量。
 格式:
声明property的语法为:@property (参数1,参数2) 类型 名字;
其中参数主要分为三类:
  • 读写属性: (readwrite/readonly)
  • setter语意:(assign/retain/copy) 
  • 原子性: (atomicity/nonatomic)
各参数意义如下:
  • readwrite: 产生setter\getter方法
  • readonly: 只产生简单的getter,没有setter。(此时重写getter方法时,不可以用下划线属性,比如_age。必须也得先声明,比如:@synthesize age =_age,此时重写getter方法时才可以用_age);
  • assign: 默认类型,setter方法直接赋值,而不进行retain操作
  • retain: setter方法对参数进行release旧值,再retain新值。该属性与 strong 一致;只是可读性更强一些。
  • copy: setter方法进行Copy操作,与retain一样,与 strong 的区别是声明变量是拷贝对象的持有者。
  • nonatomic: 禁止多线程,变量保护,提高性能
1.读写特性:readonly 、readwrite
在Objective-C中,拥有这样两个读写特性:readwrite和readonly,意思简单明了,就是可读可写以及只读。默认情况下,属性默认是可读可写的。
readwrite,声明此属性为读写属性,即可以访问设置方法(setter),也可以访问获取方法(getter),与readonly互斥。
readonly,声明此属性为只读属性,只能访问此属性对应的获取方法(getter),与readwrite互斥。
2.setter语意
setter语意特性主要是用来告诉Xcode,对于这个属性,应该如何去自动实现它的setter方法。这个特性主要是针对非ARC情况的。
 在Objective-C中,拥有三个setter语意特性:assign、retain和copy,默认情况下属性特性是assign的。
 assign:简单赋值特性,它不会对索引计数(Reference Counting)进行更改。默认类型,setter方法直接赋值,而不进行retain操作
-(void)setStr:(NSString*)value{  
   str=value;  
}
 retain:setter方法释放(release)旧的对象,然后将旧对象的值赋予输入对象,再将输入对象的索引计数增加1(retain)。
-(void)setStr:(NSString*)v{  
   if(v!=str){  
       [str release];  
       str=[v retain];
   }  
}
声明在setter方法中,需要对设过来的值进行retain 加1操作。如:
1. -(void)setName:(NSString*)_name{  
2.      //首先判断是否与旧对象一致,如果不一致进行赋值。  
3.      //因为如果是一个对象的话,进行if内的代码会造成一个极端的情况:当此name的retain为1时,使此次的set操作让实例name提前释放,而达不到赋值目的。  
4.      if ( name != _name){  
5.           [name release];  
6.           name = [_name retain];  
7.      }  
8. }
 copy:setter方法进行Copy操作,与retain一样,建立一个索引计数为1的对象,释放掉旧对象。
-(void)setStr:(NSString*)v{  
   if(v!=str){  
       [str release];  
       str=[v copy];
   }  
}
参数中比较复杂的是retain和copy,具体分析如下:
getter 分析
1、
1. @property(nonatomic,retain)test* thetest;  
2. @property(nonatomic ,copy)test* thetest; 
等效代码:
1. -(void)thetest  
2. {  
3.   return thetest;  
4. } 
2、
1. @property(retain)test* thetest;  
2. @property(copy)test* thetest; 
等效代码:
1. -(void)thetest  
2. {  
3.     [thetest retain];  
4.     return [thetest autorelease];  
5. } 
setter分析
1、
1. @property(nonatomic,retain)test* thetest;  
2. @property(retain)test* thetest;  
 
等效于:
1. -(void)setThetest:(test *)newThetest {  
2.     if (thetest!= newThetest) {  
3.         [thetestrelease];  
4.         thetest= [newThetest retain];  
5.     }  
6. } 
2、
1. @property(nonatomic,copy)test* thetest;  
2. @property(copy)test* thetest; 
等效于:
1. -(void)setThetest:(test *)newThetest {  
2.     if (thetest!= newThetest) {  
3.         [thetest release];  
4.         thetest= [newThetest copy];  
5.     }  
6. }  
retain 
代码说明
如果只是@property NSString*str; 则通过@synthesize自动生成的setter代码为:
1. -(void)setStr:(NSString*)value{  
2.     str=value;  
3. }  
如果是@property(retain)NSString*str; 则自动的setter内容为:
1. -(void)setStr:(NSString*)v{  
2.     if(v!=str){  
3.         [str release];  
4.         str=[v retain];  
5.     }  
6. } 
什么时候使用这些语意特性呢?
只要是值类型、简单类型的类型,比如说NSInteger、CGPoint、CGFloat,以及C数据类型int、float、double,bool等,都应该使用assign。
 
那么对于含有可深复制子类的对象,比如说NSArray、NSSet、NSDictionary、NSData、NSString等等,都应该使用copy特性。
 
注意:对于NSMutableArray之类的可变类型,不能够使用Copy特性,否则初始化会出现错误。
至于其他的NSObject对象,那么都应该使用retain来进行操作,这也是绝大多数所使用的情况。
 
3.所有者特性
 
我们先来看看与所有权有关系的属性,关键字间的对应关系。
属性值                      关键字               所有权
strong __strong 有
weak __weak 无
unsafe_unretained __unsafe_unretained 无
copy __strong 有
assign __unsafe_unretained 无
retain __strong 有
strong
该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。
 
weak
该属性对应 __weak 关键字,与 __weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被抛弃之后,对象将被自动赋值nil。
 
并且,delegate 和 Outlet 应该用 weak 属性来声明。同时 iOS 5 之前的版本是没有 __weak 关键字的,所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。
 
   unsafe_unretained
 
等效于__unsafe_unretaind关键字声明的变量;像上面说明的,iOS 5之前的系统用该属性代替 weak 来使用。
 
 
对于ARC来说,上一节中所说的getter语意特性将被所有者特性所代替。
 
在Objective-C中,拥有两个所有者特性:strong和weak。默认情况下属性特性是strong的。
 
对于strong来说,它就相当于getter语意特性中的retain特性,即这个特性的属性将会成为对象的持有者。这个特性称之为强引用。
@property(strong) MyClass *myObject;
相当于@property(retain) MyClass *myObject;
 
对于weak来说,它声明的属性不会拥有这个对象的所有权,如果弱引用指向的对象被deallocated的话,弱引用的对象会被自动设置为nil。
@property(weak) MyOtherClass *delegate;
相当于@property(assign) MyOtherClass *delegate;
 
简单讲strong等同retain
weak比assign多了一个功能,当对象消失后自动把指针变成nil,好处不言而喻。
 
强引用与弱引用的广义区别:
 强引用也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示列表中,则此对象会被从内存中释放。
 弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个弱引用,只要没有强引用指向他,那麽其还是会被清除。
 
面对ARC机制中,最令人头疼的就是“循环强引用”的问题,所谓循环强引用,就是我们申请了两个保险柜,然后分别将另外一个保险柜的钥匙锁在了保险柜当中。这样就会造成什么现象呢?我们完全就无法归还钥匙了,这两个保险柜就无法再重新使用了。那么使用弱引用,就不会出现这个问题了。
weak常用于网络delegate属性
 
原子特性
 
原子特性,简要来说,是针对多线程而设置的。Objective-C拥有两种原子特性,分别是atomic和nonatomic。
相比之下,swift目前还不支持这些特性。如果我们要实现线程安全,似乎只能使用objc_sync_enter此类的方法,来保证属性的处理只有一个线程在进行。或者使用属性观察器来完成这些操作。
如果使用多线程,有时会出现两个线程互相等待对方导致锁死的情况(具体可以搜下线程方面的注意事项去了解)。在没有(nonatomic)的情况下,即默认(atomic),会防止这种线程互斥出现,但是会消耗一定的资源,而如果使用nonatomic,就不会有这种阻止死锁的功能,但是如果我们确定不使用多线程的话,那么使用这个特性可以极大地改善应用性能,所以如果不是多线程的程序,打上(nonatomic)即可。
有个评友说的,感觉挺到位的:nonatomic 和 atomic 之间的根本区别不是死不死锁或者能不能阻止死锁,而是产不产生竞争。如果用atomic,那么编译器生成的set方法会在整个set逻辑外层加互斥锁,保证set动作是原子的,如果用nonatomic,那么就不会加互斥锁,所以多线程下同时set会有数据混乱的风险,但是atomic版本因为有互斥锁,等锁和释放锁都会有开销,所以影响性能。总之,只要不是自己乱写set,get,是不会有死锁问题的,而是等锁开销。
总结
我们总共介绍了四种属性特性,分别是读写特性、setter语意特性、所有者特性和原子特性。ARC是不支持setter语意特性的,它使用所有者特性。
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
参考:
http://www.jianshu.com/p/bcf734db475c
http://justcoding.iteye.com/blog/1444548
 
 
 
 
 

以上是关于Objective-C中的@property和@synthesize用法的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C中的@property和@synthesize用法

Objective-c 中的 @property 和 @synthesize

Objective-C中的@property

知识梳理Objective-C中的@property

Objective-C中的@Property具体解释

Objective-C基础笔记@property和@synthesize