一、前言
一个object的属性允许其他object监督和改变他的状态。但是在一个设计良好的面向对象程序中,直接访问一个object的内部状态是不可能的。相反,存取器(getter setter)方法是一个抽象相互作用object的底层数据。
通过访问器方法与属性进行交互
@property指令的目标是通过自动的创建这些存取器方法使创建和配置属性变得更加简单。它允许你在语义级别上指定公有属性的行为。而且它比较关注你的详细实现。
这个模型调查各种各样的属性,这些属性可以让你修改getter和setter行为。其中的一些属性确定是如何处理内存的,所以这个模型也服务于在Objective-C中对内存管理的实际的介绍。
 二、@property指令
首先,让我们看一下当我们直接使用@property时发生了什么事情,考虑一下下面的程序,一个Car类和它的实现。
Car.h
#import <Foundation/Foundation.h>@interface Car : NSObject@property BOOL running;
@endCar.m#import "Car.h"@implementation Car@synthesize running = _running;   //Xcode 4.4以上可选
@end

  

编译器会为running属性创建一个getter和setter方法。默认的命名习惯是用属性自己作为getter,加上前缀set作为setter方法,并且在前面加下划线作为实例变量,就像下面这样:
-(BOOL)running
{return _running;
}
-(void)setRunning:(BOOL)running
{_running = running;
}
当用

@property直接生成属性,你可以直接调用这些方法,就像这些方法就是包含在该类的interface和实现文件中。你也可以在.m中重写他们,但是这样会使得@synthesize指令强制。然而,你应该很少需要传统的存取器尽管@property属性供这样做在抽象的级别。
属性访问可以是用类实例后加.访问。所以看下面的代码:
Car *honda = [[Car alloc] init];honda.running = YES;NSLog(@"%d",honda.running);  

当执行honda.running时,也就是调用setRunning:方法。
当给他分配值并且运行时,就是调用getter方法。
为了改变这种存取器方式,我们可以在@properry后加括号指定,下面就是介绍可用的属性。
1、The getter= and setter= Attributes     
如果我们不喜欢@property默认的命名方式,我们可以通过The getter= and setter= Attributes 来改变存取器方法名。最常用的就是对Boolean属性使用这个。可以把getter把惯例的改成is,例如:

 @property(getter=isRunning) BOOL running;

现在生成存储器叫做isRunning和setRunning.而标注公共性质还是叫做running。下面是我们应该怎么用逗号使用它。
 Car *honda = [[Car alloc] init];honda.running = YES;NSLog(@"%d",honda.running);NSLog(@"%d",[honda isRunning]);

这些是唯一的属性,他们都是boolean标记。
2、readonly属性
readonly属性是一个很方便的方法让你的属性只读。这样会省略setter方法,并且防止作恶通过.调用,但是getter不受影响。例如,我们修改running的属性为readonly,注:我们可以制定多个属性,然后用“,”分开:
#import <Foundation/Foundation.h>
@interface Car : NSObject@property(getter=isRunning,readonly) BOOL running;-(void)startEngine;
-(void)stopEngine;
@end

  

不是让其他object改变running的属性,我们将会设置两个方法去访问。这两个方法的而实现如下:
-(void)startEngine
{_running = YES;
}
-(void)stopEngine
{_running = NO;
}

要记得,@property还为我们生成了一个实例变量,这就是我们为什么可以访问_running在没有声明的条件下(我们也可以直接使用self.running因为这个属性是只读的)。让我们来运行下列代码测试:
   Car *honda = [[Car alloc] init];
//    honda.running = YES;NSLog(@"%d",honda.running);honda.running = NO;

我们会发现最后一句出错,因为它是只读属性,无法修改。
到这个地方,我们可以很方便快捷地让我们避免书写样板的getter和setter方法。而对remaining属性,这不是一个好的情况。他们也只适用于属性存储OC对象(相当于C数据类型)。
3、nonatomic属性  
原子性(Atomicity)的作用是属性在线程的环境中怎么行为。当你不仅仅有一个线程, 那么getter和setter可能会在同一时间去调用,这就意味着getter/setter可能会被另一个方法打扰,很有可能造成数据错误。
原子的属性会封锁object,防止这种情况发生,确保get或者set操作的操作对象是完整的。没有被损坏。然而,这仅仅是一个线程安全的方面,我们必须要理解这一点。使用原子性并不能确保我们的代码就是线程安全的。
属性用@property声明默认是原子性的,这会导致一些花销,因此,如果你不是处在多线程环境(或者你正实现你自己的线程安全),你会用notatomic属性重写这个行为,就像下边:
   @property (nonatomic) NSString *model;  //设置非原子性

当使用原子性属性时,会有一个小的而且比较实际的警告。针对原子属性的属性访问器必须要么是生成的,要么是用户自定义的,只有传统非原子性的属性会让你混合搭配合成存储方法。你可以看一下,如果移去nonatomic从上边的代码,然后再Car.m添加传统的getter。
会产生一个警告:Setter和getter必须被合成,或者用户自定义,或者属性必须是nonatomic
4、内存管理
在面向对象语言中,objects存在于计算机内存中,尤其在移动设备中,内存这是一个很缺乏的资源。内存管理系统以一个高效的管理方式创建和破坏object,目标就是确保程序不占用超出它所需要的空间。
许多语言都是通过垃圾回收去完成的,但是OC用的是一个更加高效替代品,就是Object ownership(目标拥有者)。当你开始与对象交互时,你会告诉对象自己,这就意味着它确保只要你再使用对象,它就会存在.当你不再使用的时候,你放弃所有权,如果对象没有其他的所有者,操作系统会销毁这个对象,然后释放底层内存资源。
随着自动引用计数(ARC)出现,编译器自动管理你所有的对象,大多数情况下,意味着你从来不必担心内存管理系统是怎么工作的,但是,你必须明白strong,weak和copy属性,因为他们告诉编译器对象应该有什么关系。
5、strong属性
无论对象被指定为什么属性,强壮的属性可以创建拥有关系,这对所有对象属性来说是一种内隐行为,它默认是安全的,因为只要它被指定为strong属性,它就会确保对对象的值存在。
通过下面的例子,让我们看一下它是怎么工作的。
@interface Person : NSObject@property(nonatomic)NSString *name;
@end

它的实现如下,它@property产生的使用默认的存储方法,它也重写了NSObject的描述方法,返回一个代表该对象的字符串。
#import "Person.h"@implementation Person-(NSString *)description
{return self.name;
}
@end

然后,让我们添加Person属性给车,改变Car.h如下:
#import <Foundation/Foundation.h>
#import "Person.h"@interface Car : NSObject@property (nonatomic) NSString *model;
@property(nonatomic,strong) Person *driver;@end

然后考虑下边的代码: 
    Person *john = [[Person alloc] init];john.name = @"John";Car *honda = [[Car alloc] init];honda.model = @"Honda Civic";honda.driver = john;NSLog(@"%@ is driving the %@",honda.driver,honda.model);

只要driver是一个strong关联,honda对象就会持有john,这确保只要honda需要它,它就会有效。
6、weak属性
大多数情况下,强属性可以直观知道你想要什么对象属性,强引用会暴漏一个问题,例如,我们需要从driver引用他正在开的Car对象,     首先,我们需要给Person添加一个car属性:
Person.h
#import <Foundation/Foundation.h>@class Car;@interface Person : NSObject@property(nonatomic)NSString *name;
@property(nonatomic,strong)Car *car;@end

@class Car 是对Car类的前声明,就像它告诉编译器,“相信我,Car类是存在的,所有不要想着去立刻找到它”。我们不用#import这样做,因为Car也导入了Person.h,那样我们会陷入无尽的导入循环(编译器不喜欢无穷的循环)。
然后,添加下面的代码,在honda、driver分配后:
Person *john = [[Person alloc] init];john.name = @"John";Car *honda = [[Car alloc] init];honda.model = @"Honda Civic";honda.driver = john;john.car = honda;  //添加这行NSLog(@"%@ is driving the %@",honda.driver,honda.model);

这样我们现在有一个现象,就是john拥有honda,honda拥有john。这就意味着他们相互拥有,所以尽管他们不再有用,内存管理系统也不能够释放他们。
这叫做 retain cycle(保持循环),是一种内存泄露的形式,内存泄露是很不好的。幸运的是,要想解决这个办法很简单,只需要告诉其中一个属性维持一个weak属性引用另一个对象。在Person.h中,改变car的声明:
@property(nonatomic,weak)Car *car;

这种weak(弱)属性会给car创建一个非拥有关系。它允许john有一个honda的引用,同时避免了保持循环。但是,还有一个可能性就是honda会被销毁,而这个时候john正在引用honda,如果这种情况发生,weak属性会很方便地设置car为nil,去避免悬挂指针。
一个在Person中弱引用car
一个公用的使用weak属性例子就是父亲-孩子数据结构,根据约定,父对象应该保持一个强引用对子对象,子对象应该存储一个弱引用父对象。弱引用在代理设计模式中是内在的,也就是自带的。
重点是两个对象不恩给你都是强引用彼此,weak属性让保持一个不通过创建保持循环循环的关系变成可能。

7、copy属性

它是strong的替代品,不是保持拥有一个存在的对象,而是创建一个引用,无论你指定什么属性,都会持有这个拥有。只有符合NSCopying protocol的对象才能使用这个属性。
代表值的属性(相对于链接或关系)是一个使用copy的不错选择。例如,开发者通常复制字符串属性,而不是强引用它们:
//Car.h
@property (nonatomic,copy) NSString *model;
现在Car将会存储一个全新的实例,不管我们指定的model值,如果你处理可变的值,它会有一个好处,就是冻结对象无论什么时候有值当它被指定时。演示如下:
         Car *honda = [[Car alloc] init];honda.model = @"Honda Civic";NSMutableString *model = [NSMutableString stringWithString:@"Honda Civic"];honda.model = model;NSLog(@"%@",honda.model);[model setString:@"Nissa Versa"];  NSLog(@"%@",honda.model); //输出结果还是Honda Civic

NSMutableString 是NSString的一个子类,它可以在自身的基础上修改它的值。如果model属性不被声明为copy属性,我们将会看到在最后一个NSLog将会输出Nissa Versa
8、其他属性
上面的的这些@property性质我们需要使用在如今的OC应用中,但是下面的一些属性我们可能会在老得类库或者文档中偶尔遇到。
  • retain属性
retain属性是手动释放保留版本的strong,它有准确一样的影响:为指定的values声称所有权.ARC环境中不能使用。
  • unsafe_unretained属性
它类似与weak,但是如果引用对象销毁,不自动设置nil。使用该属性的唯一原因就是:去让你的类兼容不支持weak属性的代码。
  • assign属性
当给一个这个属性指定一个新的value,assign属性不执行任何类型的内存管理调用。这个一个原始数据类型的默认行为,它的应用是在iOS5之前去实现弱引用,就像retain,现在的application你不应该明确的使用。
总结:
这个模块讲解了所有的@property选择属性,下面是总结属性:
  1. getter=  让getter方法使用自定义的名字
  2. setter = 让setter方法使用自定义名字
  3. readonly 不合成setter方法
  4. nonatomic 不保证在多线程环境下存取访问器的完整性,这比原子性更加高效
  5. strong 在属性和指定value之间创建一个拥有关系,这是默认的对象属性
  6. weak 在属性和制定value之间创建一个不拥有关系,使用这个防止循环引用
  7. copy 创建一个指定值的副本,而不是引用存在的对象实例。
三、参考
参考资料: http://rypress.com/tutorials/cocoa/
四、更新 2018-04-08更新
1.这里需要注意:我们所谓的所有属性关键字都是在设置方法时才触发,也就是说现在有一个name的属性,如果使用_name,那么属性关键字不会生效,因为这些关键词都是在setter中才能起作用。举个例子:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,copy)NSArray *constArr;
@property (nonatomic,strong)NSMutableArray *mArr;
@property (nonatomic,strong)NSString *name;
@end
@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];_mArr = [[NSMutableArray alloc] initWithObjects:@"1",@"2", nil];_constArr = _mArr;NSLog(@"%@",self.constArr);[_mArr addObject:@"3"];NSLog(@"%@",self.constArr);
}
@end

这个例子中,虽然我们对constArr使用的是copy,但是两次打印的结果是不一样的。如果我们这样写:

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,copy)NSArray *constArr;
@property (nonatomic,strong)NSMutableArray *mArr;
@property (nonatomic,strong)NSString *name;
@end
@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];_mArr = [[NSMutableArray alloc] initWithObjects:@"1",@"2", nil];self.constArr = _mArr;NSLog(@"%@",self.constArr);[_mArr addObject:@"3"];NSLog(@"%@",self.constArr);
}
@end

输出打印的结果才会是一样的,因为前者只是对实例变量的指针赋值,而后者才是利用了属性特性,对属性进行赋值。这也正解释了我们平时所理解的:

对于strong,为这种属性设置新值得时候,设置方法会先保留新值,并释放旧值,然后将新值设置上去。

对于copy,设置方法并不保留新值,而是将其拷贝。

上面提到的设置方法就是我们说的setter,也就是后者使用self.constArr调用的方法。

转载于:https://www.cnblogs.com/zhanggui/p/4656427.html

@property括号内属性讲解相关推荐

  1. Python - @property 方法变属性

    @property @property是内置的装饰器,与普通装饰器原理是一样的,只不过返回的不是函数,而是类对象. @property负责把一个方法变成属性进行调用,保证对参数进行必要的检查. 属性有 ...

  2. python正则匹配括号内任意字符,python 正则匹配 获取括号内字符

    一.需求 * 提取字典中的[]内的字符,生成可以导入到五笔词库中的txt文件. 原文件: 生成后的结果: 实现方式 前言 因为正则表达式语法很难读,因此本次程序以多次的方式来讲解. 一.提取[]内内容 ...

  3. association内属性及作用

    嵌套查询association内属性及作用 多对一 多表查询 <select id="getUserRolePageList" resultMap="roleLis ...

  4. oracle取括号内数字,怎么把excel中一列文本中括号里的数字弄出来啊

    公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解. 话题:怎么把excel中一列文本中括号里的数字弄出来啊回答:=MID(A1,FIND("(",A1)+1,FIND(")",A1)-FIN ...

  5. 计算机右键括号内的字母,word软体选单中每个选项旁边都有个带括号的字母,是什么意思?...

    word软体选单中每个选项旁边都有个带括号的字母,是什么意思?以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! word软 ...

  6. java 正则 任意字符_Java正则表达式 去掉括号内任意字符

    前言: 刚开始以为 (.*) 就是括号内任意字符了,试了不行. 错误点 1.括号需要转义(是正则表达式关键字) 2.不是任意字符,而是 除了右括号的任意字符 String content = &quo ...

  7. python正则group()的用法—正则提取括号内以及其他符号内内容

    python正则提取括号内以及其他符号内内容,我以前学过一点点正则,但是学的不深,用的正则也是最笨的正则方法,只会group(0). 然而,我今天又看了下正则,发现正则的提取确实好用.无论爬虫还是文本 ...

  8. linux 内存显示括号内字母的含义

    当linux系统发生异常或者 echo 'm' > /proc/sysrq-trigger 我们会看到类似以下的信息,其中括号内字符代表什么含义呢?我们跟踪 sysrq-trigger,看看源码 ...

  9. 关于@property()的那些属性及ARC简介【nonatomic,atomic,assign,retain,strong,weak,copy。】

    @property()常用的属性有:nonatomic,atomic,assign,retain,strong,weak,copy. 其中atomic和nonatomic用来决定编译器生成的gette ...

最新文章

  1. 求助大神!怎样除去XML节点反复的值的数据
  2. how is crmd_product_i inserted to db
  3. Rabbitmq如何设置优先级队列?如何限流?如何重试?如何处理幂等性?
  4. Dev的多语言简单实现
  5. Windows IOCP模型与Linux EPOLL模块之比较-
  6. Spring Data Jpa 查询返回自定义对象
  7. 门诊管理系统开发能提高医生的诊疗水平和质量吗
  8. 证明同步函数使用的this锁
  9. 上号神器扫码登录网站使用教程
  10. 服务器带宽上行与下行是什么意思,有什么区别
  11. 关系数据库——关系操作关系模型的完整性
  12. Dijkstra迪杰斯特算法(C++版本和JAVA版本)
  13. python实现图片上打印文字
  14. 电路板Layout爬电距离、电气间隙的确定
  15. 微软默默给 curl 捐赠一万美元,半年后才通知
  16. 逆水寒服务器紫荆之巅有关消息,逆水寒ol:官方钦定19个热门服务器?四大服舞阳城门口人们为患!...
  17. Install cf v6
  18. iOS OC Sugars collection
  19. 终于有人把云计算与数据库的关系讲明白了
  20. ActiveX 控件注册的几种方法 VC++编写

热门文章

  1. python人工智能学习笔记_[Python] 人工智能与自然语言处理学习笔记(1)
  2. from mysql partition select_通过分区(Partition)提升MySQL性能[原创翻译]
  3. java poi教程_Java完成POI的功能
  4. 计算两个经纬度的距离_HTML5 地理定位+地图 API:计算用户到商家的距离
  5. java非法字符检测_Java Web 一些特殊字符的过滤(appscan检查的安全问题)
  6. opengl 实时波形显示_OpenGL1------OpenGL概述
  7. 104.202.60.2/.index.php,web扫描
  8. java 静态方法 构造方法,Java构造函数和静态方法
  9. python汇总数据的程序_Python数据处理常用程序模块汇总
  10. @RunWith@ContextConfiguration进行Spring上下文测试报错