iOS:属性、修饰词(内存管理) 及其对应成员变量 、ARC

原创
2016/01/11 15:35
阅读数 179


------------早期GCC版本------------

--@property A作用就是让编译器在h文件声明A 的setter/getter方法

--@synthesize A作用就是让编译器在m文件生成A 的setter/getter方法;(如果自己实现了setter/getter方法,则以自己实现为准)

--要求必须要成员变量A 对应属性;或者将名称不一样成员变量_A对应属性A,即@synthesize A = _A; 

--另外,属性的retain、assign、copy等修饰词就是在setter方法里retain/release等额外操作;

 ------------现在LLVM版本------------

--@property A作用强大了,除了原有作用;同时还Default synthesis of @property instance variables and accessor methods;具体:

1..如果发现m中没有@synthesize,则"Autosynthesized A= _A"(补上synthesize和匹配的_A);有@synthesize,不做处理;

2.根据m中@synthesize中匹配的实例变量查看有没有,若没有创建之。(@synthesize A匹配的实例变量为A;@synthesize A = _A 匹配的实例变量为_A)

--上叙俩规则根据例子总结,未找到相关文档说明:

--例子1;只有@property A ;那么m中 _A 能用,A 不能用;

--例子2;有@property A + 成员变量A; 那么 _A 能用,A能用;

--例子2:  有@property A + @synthesize A;那么 _A 不能,A 能用;

--例子3;有@property A + @synthesize A + 成员变量_A;那么 _A 能用,A 都能用;

--例子4;有@property A + @synthesize A=_A + 成员变量_A; 那么 _A 能用,A 不能用;

--一个经典例子,类中有属性@property(nonatomic,strong)IBOutlet UIButton *aButton;  和成员变量IBOutlet UIButton *_aButton; 没有@synthesize;他俩分别关联button1,和button2,运行程序,不管是self.aButton 还是_aButton都是指向button1;说明@property在编译的时候起作用,将_aButton 和属性aButton关联为一个。如果属性和成员变量是一样的,则一个关联button1,另一个也关联了。

 ------------类别中的属性property ------------
--类与类别中添加的属性要区分开来,因为类别中只能添加方法,不能添加实例变量。经常会在ios的代码中看到在类别中添加属性,这种情况下,是不会自动生成实例变量的。例:UINavigationController.h中会对UIViewController类进行扩展

[objc] view plaincopy在CODE上查看代码片派生到我的代码片

  1. @interface UIViewController (UINavigationControllerItem)  

  2. @property(nonatomic,readonly,retainUINavigationItem *navigationItem;  

  3. @property(nonatomicBOOL hidesBottomBarWhenPushed;  

  4. @property(nonatomic,readonly,retainUINavigationController *navigationController;  

  5. @end  

  这里添加的属性,不会自动生成实例变量,这里添加的属性其实是添加的getter与setter方法。

  注意一点,匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)

============修饰词============

主要分为三类:

1.原子性(Atomicity)包含:nonatomic;

2.读写属性(Writability)包含:readwrite / readonly;
3.setter语义(Setter Semantics)包含:assign / retain / copy;

------原子性

nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问。默认值是atomic,为原子操作。(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)

------读写属性
readwrite / readonly:决定是否生成set访问器,readwrite是默认属性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用

注意:readwrite/readonly配合使用:属性在外部是只读,自己使用时读写-->re-declare the property in a class extension

[objc] view plaincopy在CODE上查看代码片派生到我的代码片

  1. @property(nonatomic,readonly)NSString *myName; //在.h 中  

  2. self.myName = @"ss"; 不能用;而 _myName = @"ss" 能用   //在.m中  

  3. //re-declare the property in a class extension  

  4. @interface ViewController ()    

  5. @property(nonatomic,readwrite)NSString *myName;  

  6. @end   

  7. self.myName = @"ss"; 和  _myName = @"ss"  都能用   

------setter语义

        这些属性用于指定set访问器的语义,也就是说,这些属性决定了以何种方式对数据成员赋予新值。
--assign:直接赋值,索引计数不改变,适用于简单数据类型,例如:NSIngeter、CGFloat、int、char等。
--retain:指针的拷贝,使用的是原来的内存空间。对象的索引计数加1。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。
--copy:对象的拷贝,新申请一块内存空间,并把原始内容复制到那片空间。新对象的索引计数为1。此属性只对那些实行了NSCopying协议的对象类型有效。

        很多Objective-C中的object最好使用用retain,一些特别的object(例如:string)使用copy

============自定义setter/getter方法============

[html] view plaincopy

  1. // 1,当把语义特性声明为assign时,setter和getter时方法内部实现  

  2. - (void)setName:(NSString *)name{  

  3.   _name = name;  

  4. }  

  5. - (NSString *)name{  

  6.  return _name;  

  7. }  

  8. //2,当把语义特性声明为retain时,setter和getter方法内部实现  

  9. - (void)setName:(NSString *)name{  

  10. if (_name != name) {  

  11. [ _name release];  

  12. _name = [name retain];  

  13. }  

  14. }  

  15. - (NSString *)name{  

  16. return [[ _name retain] autorelease];  

  17. }  

  18. //3,当把语义特性声明为copy时,setter和getter方法内部实现  

  19. - (void)setName:(NSString *)name{  

  20. if (_name != name) {  

  21. [ _name release];  

  22. _name = [name copy];  

  23. }  

  24. }  

  25. - (NSString *)name{  

  26. return [[ _name retain] autorelease];  

  27. }  

      注意自定setter方法的书写,以前为了“安全”都在releae后面赋了一个nil的值。这样写是错误的,尤其对于retain的语音,因为有可能别的对象retain的它持有的对象,结果值被置为nil了。另不用担心初始的时候_name 就release了一次,因为类的成员中对象的初始值都是nil。

[html] view plaincopy

  1. if (_name != name) {  

  2. [ _name release];  

  3.  _name = nil;  

  4.  _name = [name retain];  

  5. }  

  6. }  


展开阅读全文
打赏
1
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
1
分享
返回顶部
顶部