OC中@property的各种属性的使用详解
2015-08-10 20:46
501 查看
1 、在obj2.0中可以声明属性让编译器自动合成setter和getter方法:
所用关键字:@property和@synthesize。二者需要配对使用。@property是在头文件的类中对setter和getter方法进行声明的,而@synthesize是在.m文件内对声明的方法进行实现的,格式如下:
@synthesize 成员名1,成员名2,,,
而在对应的.h文件中@property的使用方法如下:@property(属性参数1,属性参数2) 成员类型 成员名
2、 而property的属性参数有atomic,nonatomic,assign,retain,copy,strong,weak等属性,具体介绍如下:
(1)atomic//默认属性
A:当一个变量声明为atomic时,意味着在多线程中只能有一个线程对它进行访问
B:当一个变量声明为atomic时,该变量为线程安全型,但是会影响访问速度。
C:当一个变量声明为atomic时,在非ARC编译环境下,需要设置访问锁保证对该变量进行正确的get/set
在setter函数中设置访问锁格式如下:{lock},,,设置语句,,,{lock}
(2)nonatomic
A:当一个变量声明为nonatomic时,意味着多个线程可以同时对其进行访问。
B:当一个变量被声明为nonatomic时,它是非线程安全型,访问速度快。
C:当一个变量声明为nonatomic时,当两个不同的线程对其访问时容易失控。
注意:因为手机内存有限,几乎不用多线程,所以在iOS开发中,多用nonatomic属性(需手动添加)来提高访问速度
(3)assign 默认属性
简单赋值,不需要更改索引计数。应用场合:对基础数据类型(例如NSInteger,CGFloat)和c数据类型(int,float,double,char 等)
(4)retain (引用)
与strong对应,使用了引用计数,retain+1,retain-1;当引用计数retaincount=0时,delloc会被调用,内存释放。retain实际就是(指针拷贝,引用计数器加一),对于“对象1指针=[对象2指针 retain]”的方式赋值,表示将对象2的指针拷贝一份赋给对象1指针,对象1与对象2共有的计数器变量 加一 retaincount++;
[对象1.retaincount]=[对象2.retaincount]=retaincount++。对于所有用retain方式赋值的对象,他们共享同一个引用计数器,表示一共有几个指针同时使用(指向并绑定)一个公共对象。用一句话概括:retain就是利用指针拷贝和引用计数的方式将多个指针绑定到同一资源(对象)上。对于@property中的retain属性的自动调用过程就是先将一个对象释放引用(调用release)一次,再进行以上的retain方式赋值。retain的应用场合是对应于一般的Object,例如NSObject等。(注意:调用release(以[指针
release] 的方式)释放值为nil的未初始化指针或者被赋过nil值的指针不会出现错误)
(5)copy
用于非共享内存时,每个指针都有自己的内存空间,用于NSString对象指针。在@property中使用属性copy时,先将一个对象(假设为A指针)release一下(引用释放一下),再为它开辟一块和另一个对象(假设为B指针)指针指向的内存同样大小的内存空间,把这片新开辟内存的首地址赋给A进行绑定,把B指向堆空间的内容写进A指向的内存,并把新的对象指针A的引用计数器赋值为1,而B的不变。换句话就是赋值后,赋值对象B无任何改变,被赋值的新对象指针A被赋新的值绑定了新的且和赋值对象指针B指向堆空间内容完全相同的堆空间,并把计数器retain为1;
注意:retain和copy的区别就是:
copy其实是建立了一个相同的对象,而retain只是保存其对象,并且其计数值+1。
例如:一个NSString对象,地址为0×1000,内容为@”string”
copy到另外一个NSString之后,地址为0×2000,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,但是这个新对象的retain值+1,并释放旧的对象。
也就是说,retain是指针拷贝,copy是内容拷贝
(6)readonly
此关键字代表设置属性的setter方法不会被生成,所以它不可以和resign/copy/assign 组合使用
(7)readwrite 默认属性 有setter和getter方法
(9)strong 与weak
strong是ARC环境下的默认属性,二者都为ARC新引入的对象变量属性。strong相当于retain。weak相当于assign。
ARC引入了新的对象的新生命周期限定,即零弱引用。如果零弱引用被deallocated的话,零弱引用的对象指针会被设置为nil。weak比assign多了一个功能,当对象消失后自动把指针变成nil。
大致图解如下:
3. 如果实现了了@property和@synthesize,就不需要再手动的提供setter和getter方法了。实现了@property和@synthesize相当于为指定的成员变量声明并实现了方法名为“-(void)set+成员名其首字母大写:(成员类型)参数名”
的setter方法和“-(成员类型)成员名”的getter方法。 例如假设有成员变量int age;假设为它实现了自动setter和getter方法,就相当于声明并实现了”-(void)setAge:(int) _age“的setter方法和“- (int)age ”的getter方法。
注意:
(1)正是因为@property和@synthesize实现了以上两种类型的方法,在main中调用时才可以用“对象指针.成员变量”的方式为其赋值和输出(其实质就是间接的调用了以上两种格式的setter和getter方法)。如果没有为成员变量实现@property属性且没有手动的为成员变量提供以上两种格式的setter和getter方法(或提供了setter与getter方法但不是以上两种格式) 在外部用对象指针加点的方式访问成员变量,就会编译错误。
(2)在为某成员变量实现了@property和@synthesize的配套属性的情况下:如果再手动为该成员变量提供了和@property自动提供的setter和getter方法名相同的setter/getter方法时,编译器会先检查手动提供的方法,如果有同名的方法时就以手动提供的为主。如果手动提供的方法名和自动提供的不一致时,当用“对象指针.成员变量”的方式进行访问时就直接调用@property自动提供的方法。
4. 在类声明中的{}内如果声明了某成员变量,在{}之外如果用@property对该成员变量进行set/get方法声明实现时,表示的就是对已有成员进行方法设置。如果{}内没有声明该成员变量的话,就表示@property先为类声明了一个成员变量,然后再为其提供set/get的方法声明。
代码验证,实例如下:
在XYPoint.h中编辑代码如下:
在XYPoint.m中编辑代码如下:
在Circle.h中编辑代码如下:
在Circle.m文件中编辑代码如下:
在main.m中调用如下:
运行结果如下:
所用关键字:@property和@synthesize。二者需要配对使用。@property是在头文件的类中对setter和getter方法进行声明的,而@synthesize是在.m文件内对声明的方法进行实现的,格式如下:
@synthesize 成员名1,成员名2,,,
而在对应的.h文件中@property的使用方法如下:@property(属性参数1,属性参数2) 成员类型 成员名
2、 而property的属性参数有atomic,nonatomic,assign,retain,copy,strong,weak等属性,具体介绍如下:
(1)atomic//默认属性
A:当一个变量声明为atomic时,意味着在多线程中只能有一个线程对它进行访问
B:当一个变量声明为atomic时,该变量为线程安全型,但是会影响访问速度。
C:当一个变量声明为atomic时,在非ARC编译环境下,需要设置访问锁保证对该变量进行正确的get/set
在setter函数中设置访问锁格式如下:{lock},,,设置语句,,,{lock}
(2)nonatomic
A:当一个变量声明为nonatomic时,意味着多个线程可以同时对其进行访问。
B:当一个变量被声明为nonatomic时,它是非线程安全型,访问速度快。
C:当一个变量声明为nonatomic时,当两个不同的线程对其访问时容易失控。
注意:因为手机内存有限,几乎不用多线程,所以在iOS开发中,多用nonatomic属性(需手动添加)来提高访问速度
(3)assign 默认属性
简单赋值,不需要更改索引计数。应用场合:对基础数据类型(例如NSInteger,CGFloat)和c数据类型(int,float,double,char 等)
(4)retain (引用)
与strong对应,使用了引用计数,retain+1,retain-1;当引用计数retaincount=0时,delloc会被调用,内存释放。retain实际就是(指针拷贝,引用计数器加一),对于“对象1指针=[对象2指针 retain]”的方式赋值,表示将对象2的指针拷贝一份赋给对象1指针,对象1与对象2共有的计数器变量 加一 retaincount++;
[对象1.retaincount]=[对象2.retaincount]=retaincount++。对于所有用retain方式赋值的对象,他们共享同一个引用计数器,表示一共有几个指针同时使用(指向并绑定)一个公共对象。用一句话概括:retain就是利用指针拷贝和引用计数的方式将多个指针绑定到同一资源(对象)上。对于@property中的retain属性的自动调用过程就是先将一个对象释放引用(调用release)一次,再进行以上的retain方式赋值。retain的应用场合是对应于一般的Object,例如NSObject等。(注意:调用release(以[指针
release] 的方式)释放值为nil的未初始化指针或者被赋过nil值的指针不会出现错误)
(5)copy
用于非共享内存时,每个指针都有自己的内存空间,用于NSString对象指针。在@property中使用属性copy时,先将一个对象(假设为A指针)release一下(引用释放一下),再为它开辟一块和另一个对象(假设为B指针)指针指向的内存同样大小的内存空间,把这片新开辟内存的首地址赋给A进行绑定,把B指向堆空间的内容写进A指向的内存,并把新的对象指针A的引用计数器赋值为1,而B的不变。换句话就是赋值后,赋值对象B无任何改变,被赋值的新对象指针A被赋新的值绑定了新的且和赋值对象指针B指向堆空间内容完全相同的堆空间,并把计数器retain为1;
注意:retain和copy的区别就是:
copy其实是建立了一个相同的对象,而retain只是保存其对象,并且其计数值+1。
例如:一个NSString对象,地址为0×1000,内容为@”string”
copy到另外一个NSString之后,地址为0×2000,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,但是这个新对象的retain值+1,并释放旧的对象。
也就是说,retain是指针拷贝,copy是内容拷贝
(6)readonly
此关键字代表设置属性的setter方法不会被生成,所以它不可以和resign/copy/assign 组合使用
(7)readwrite 默认属性 有setter和getter方法
(9)strong 与weak
strong是ARC环境下的默认属性,二者都为ARC新引入的对象变量属性。strong相当于retain。weak相当于assign。
ARC引入了新的对象的新生命周期限定,即零弱引用。如果零弱引用被deallocated的话,零弱引用的对象指针会被设置为nil。weak比assign多了一个功能,当对象消失后自动把指针变成nil。
大致图解如下:
3. 如果实现了了@property和@synthesize,就不需要再手动的提供setter和getter方法了。实现了@property和@synthesize相当于为指定的成员变量声明并实现了方法名为“-(void)set+成员名其首字母大写:(成员类型)参数名”
的setter方法和“-(成员类型)成员名”的getter方法。 例如假设有成员变量int age;假设为它实现了自动setter和getter方法,就相当于声明并实现了”-(void)setAge:(int) _age“的setter方法和“- (int)age ”的getter方法。
注意:
(1)正是因为@property和@synthesize实现了以上两种类型的方法,在main中调用时才可以用“对象指针.成员变量”的方式为其赋值和输出(其实质就是间接的调用了以上两种格式的setter和getter方法)。如果没有为成员变量实现@property属性且没有手动的为成员变量提供以上两种格式的setter和getter方法(或提供了setter与getter方法但不是以上两种格式) 在外部用对象指针加点的方式访问成员变量,就会编译错误。
(2)在为某成员变量实现了@property和@synthesize的配套属性的情况下:如果再手动为该成员变量提供了和@property自动提供的setter和getter方法名相同的setter/getter方法时,编译器会先检查手动提供的方法,如果有同名的方法时就以手动提供的为主。如果手动提供的方法名和自动提供的不一致时,当用“对象指针.成员变量”的方式进行访问时就直接调用@property自动提供的方法。
4. 在类声明中的{}内如果声明了某成员变量,在{}之外如果用@property对该成员变量进行set/get方法声明实现时,表示的就是对已有成员进行方法设置。如果{}内没有声明该成员变量的话,就表示@property先为类声明了一个成员变量,然后再为其提供set/get的方法声明。
代码验证,实例如下:
在XYPoint.h中编辑代码如下:
<span style="font-size:18px;">// // XYPoint.h // aa // // Created by apple on 15/8/8. // Copyright (c) 2015年 liu. All rights reserved. // #import <Foundation/Foundation.h> @interface XYPoint : NSObject { int x; int y; } @property int x,y; -(void)setX:(int) xVal andY:(int) yVal; @end </span>
在XYPoint.m中编辑代码如下:
<span style="font-size:18px;">// // XYPoint.m // aa // // Created by apple on 15/8/8. // Copyright (c) 2015年 liu. All rights reserved. // #import "XYPoint.h" @implementation XYPoint @synthesize x,y; -(void) setX:(int) xVal andY:(int)yVal { x=xVal; y=yVal; } @end </span>
在Circle.h中编辑代码如下:
<span style="font-size:18px;">// // Circle.h // aa // // Created by apple on 15/8/8. // Copyright (c) 2015年 liu. All rights reserved. // #import <Foundation/Foundation.h> #import "XYPoint.h" @class XYPoint;//向前声明以提高程序的运行效率 @interface Circle : NSObject { int radius; XYPoint *origin;// 定义类XYpoint的对象,作为类Circle的实例变量 } @property int radius; @property (nonatomic,retain) XYPoint *origin; //-(XYPoint *)origin; //get方法,返回类类型的实例变量 //-(void)setOrigin: (XYPoint *)pt; -(int) area; //计算面积方法 -(int) perimeter; //计算周长方法 @end </span>
在Circle.m文件中编辑代码如下:
<span style="font-size:18px;">// // Circle.m // aa // // Created by apple on 15/8/8. // Copyright (c) 2015年 liu. All rights reserved. // #import "Circle.h" @implementation Circle @synthesize radius; -(void)setOrigin:(XYPoint *)pt { origin=pt; } -(XYPoint *)origin { return origin; } -(int)area { NSLog(@"return area()"); return radius*radius*3.14; } -(int)perimeter { return radius*3.14*2; } @end </span>
在main.m中调用如下:
<span style="font-size:18px;">// // main.m // aa // // Created by apple on 15/8/8. // Copyright (c) 2015年 liu. All rights reserved. // #import <Foundation/Foundation.h> #import "Circle.h" int main(int argc, const char * argv[]) { @autoreleasepool { XYPoint * p=[[XYPoint alloc] init]; p.x=2; //当为类的成员变量实现了setter方法 才可以用“ 对象指针.实现setter方法的成员变量=新值”来进行赋值。(这种赋值方式的实质就是调用了setter方法). p.y=2; //注意对象指针可以用“. ”来调用类定义的成员方法,但不可以调用没有实现setter/getter方法的成员变量 Circle * c; NSLog(@"未初始化的c=%lu",[c retainCount]); [ c release]; NSLog(@"未初始化的c=%lu",[c retainCount]); c=[[Circle alloc] init]; c.radius=2; //[c setRadius:2] [c setRadius:3]; NSLog(@"%d",c.radius); NSLog(@"%d",c.area);//调用输出成员变量时,系统会调用它的getter()方法来进行实现输出 //c.origin=p; //同样直接给成员变量赋值时,系统会调用它的setter()方法进行实现赋值。 [c setOrigin:p]; NSLog(@"%@",c.origin); NSLog(@"%d %d",c.origin.x,c.origin.y); NSLog(@"%d %d",[[c origin] x],[[c origin] y]); NSLog(@"%lu",[c retainCount]); Circle *d=[c retain]; NSLog(@"%lu",[c retainCount]); NSLog(@"%lu",[d retainCount]); Circle *f=[d retain]; NSLog(@"%lu",[c retainCount]); NSLog(@"%lu",[d retainCount]); NSLog(@"%lu",[f retainCount]); [c release]; NSLog(@"%lu",[c retainCount]); NSLog(@"%lu",[d retainCount]); NSLog(@"%lu",[f retainCount]); [d release]; NSLog(@"%lu",[c retainCount]); NSLog(@"%lu",[d retainCount]); NSLog(@"%lu",[f retainCount]); [f release]; NSLog(@"%lu",[c retainCount]); //原本释放后c d f共享的retaincount应该为0,但是必须赋值过nil后他们的retaincount才为0 NSLog(@"%lu",[d retainCount]); NSLog(@"%lu",[f retainCount]); f=d=c=nil; //仅仅全部释放还不行,必须将他们(使用同一对象,共享retaincount的所有引用)全部(必须是全部)赋值为nil,他们的共享变量retaincount才为0,对于值为nil的指针,无论怎么release都不会出现错误。 NSLog(@"%lu",[c retainCount]); NSLog(@"%lu",[d retainCount]); NSLog(@"%lu",[f retainCount]); [p release]; } return 0; } </span>
运行结果如下:
相关文章推荐
- extern “C” 的使用
- 2.【SELinux学习笔记】概念
- ngnix配置及实战
- Linux init
- Ombrophobic Bovines
- Ombrophobic Bovines 分类: POJ 图论 最短路 查找 2015-08-10 20:32 2人阅读 评论(0) 收藏
- Tomcat关闭过程(Tomcat源码解析四)
- 3g自己主动更新网卡驱动web完架构文档
- linux系统下安装QT5.4
- 1.【SELinux学习笔记】背景
- 《SELinux by example Using security enhanced Linux》读书笔记
- 如何使用 Docker 部署一个基于 Play Framework 的 Scala Web 应用?
- 卫星导航同步时的环路更新时间架构
- Linux 中直接 I/O 机制的介绍
- 如何使用 Docker 部署一个基于 Play Framework 的 Scala Web 应用?
- Eclipse启动Tomcat时,45秒超时解决方式
- 基于64位CentOS6.4安装Tomcat8.0
- 网站jcms流程分析
- nginx封ip,禁用IP段的设置说明
- linux安装python遇到的问题