Objective-C 2.0之属性(2)——属性参数

0x01 属性声明语法

通过在@property后的括号内添加属性特质参数,可以影响存取方法的生成。

声明property的语法为:@property (参数1,参数2,...) 类型 名字

@interface Test : NSObject

// 括号内添加属性特质进行限制
@property(nonatomic, readwrite, copy) NSString *name;

@end

0x02 属性参数

属性参数的分类

属性参数主要可以分为三类:

  • 读写语义:readwrite,readonly,getter,setter
  • 内存管理语义:assign,retain,copy,unsafe_unretained
  • 拥有者属性:weak,strong
  • 原子性: atomic,nonatomic

属性参数的语义

读写语义

  • readwrite:默认的属性,变量可读可写,编译器自动生成setter / getter方法;
  • readonly:变量只读,只生成getter方法没有setter方法。但是我们可以自己补上setter方法来修改变量。

以下是readonly属性验证程序:

#import <Foundation/Foundation.h>
#import "Tire.h"

@interface AllWeatherRadial : Tire
@property (readonly) float rainHandling;
-(float)setRainHandling:(float)rainHandling;    //手动补充setter方法声明
                                                //由于是readonly属性所以必须先在接口中声明
                                                //否则虽然编译时不会报错
                                                //但程序运行过程中如果对rainHandling赋值,会因为找不到setter方法而崩溃

@property float snowHandling;                   //snowHandling默认是readwrite属性
@end // AllWeatherRadial.h

//----------------------------------------------------------------------------
//AllWeatherRadial.m
#import "AllWeatherRadial.h"

@implementation AllWeatherRadial

@synthesize rainHandling = _rainHandling;       //Xcode 4.5后的编译器并不需要这行代码

-(float)setRainHandling: (float)rh
{
    _rainHandling = rh;                         //注意这里必须使用变量名_rainHandling,记住rainHandling是属性名
}                                               //rainHandling的setter方法实现

...
//main.m文件中的代码不需要修改

readwrite 和 readonly是两个互斥属性。

  • getter = < gettername >, setter = < settername >: 可以选择性的在括号里直接指定存取方法的方法名,但有可能会破坏健/值规则。因此如非必要,尽量避免使用。在此不展开详述。

内存管理语义

  • assign:默认属性类型,是最简单的赋值特性,它不会对索引计数(Reference Counting)进行更改。变量的setter方法直接赋值,而不进行retain操作:
@property NSString *str; 

//-----------------------------------------------

-(void)setStr:(NSString*)value{  
    str=value;  
} 
  • retain:变量的setter方法释放(release)旧的对象,然后将旧对象的值赋予输入对象,再将输入对象的索引计数增加1(retain):
@property (retain) NSString *str;

//----------------------------------------

-(void)setStr:(NSString*) v{  
   if(v != str){  
       [str release];  
       str=[v retain];
   }  
}
  • copy:变量的setter方法进行Copy操作,与retain一样,建立一个索引计数为1的对象,释放掉旧对象:
@property (copy) NSString *str;

//-------------------------------------------

-(void)setStr:(NSString*) v{  
   if(v != str){  
       [str release];  
       str=[v copy];
   }  
}
  • unsafe_unretained:等效于用__unsafe_unretaind关键字声明的变量,在iOS 5.0之前的系统用该属性代替weak来使用。

语意特性的使用方法:

  • 只要是值类型、简单类型的类型,如NSInteger、CGPoint、CGFloat,以及C数据类型int、float、double,bool等,都应使用assign;
  • 对于含有可深复制子类的对象,比如说NSArray、NSSet、NSDictionary、NSData、NSString等等,都应该使用copy特性;
  • 对于NSMutableArray之类的可变类型,不能够使用Copy特性,否则初始化会出现错误;
  • 至于其他的NSObject对象,非ARC环境下都应该使用retain来进行操作,这也是绝大多数所使用的情况。

拥有者特性

对于ARC来说,上一节中所说的getter语意特性(assign、retain、copy)将被拥有者特性所代替。

  • strong:strong相当于getter语意特性中的retain,strong特性的属性将会成为对象的拥有者。这个特性称之为强引用:
@property(strong) MyClass *myObject;

//Equal to:@property(retain) MyClass *myObject;
  • weak:它声明的属性不会拥有这个对象的所有权,如果弱引用指向的对象被释放的话,弱引用的对象会被自动设置为nil。weak比assign多一个自动把对象置为nil的步骤,称为“归零弱引用”(Zeroing Weak Reference)。

强引用与弱引用的广义区别:

  • 强引用也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,则此对象会被从内存中释放;
  • 弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个弱引用,只要没有强引用指向他,那么它还是会被清除。弱引用的归零特性为我们提供了保险,避免我们使用失效的引用。

原子特性

  • atomic:原子性。原子性是数据库原理里面的一个概念,ACID中的第一个。在多线程中同一个变量可能被多个线程访问甚至更改造成数据污染,因此为了安全,Objective-C中默认是atomic的,会对对象的setter方法加锁,相应的也会付出维护原子性(数据加锁解锁等)的系统资源代价。
  • nonatomic: 非原子性。应用中如果不是特殊情况(多线程间的通讯编程),一般还是用nonatomic来修饰变量,不会对其setter方法加锁,以提高多线程并发访问时的性能。

iOS开发的建议:

  • 所有属性都声明为nonatomic;
  • 尽量避免多线程抢夺同一块资源;
  • 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。

0x03 ARC中的属性关键字

属性特性与内存管理关键字两者是互斥的关系,在启用ARC之后,属性、关键字和对应的所有权关系如下:

属性值 关键字 所有权

strong

__strong
weak __weak
unsafe_unretained __unsafe_unretained
copy __strong
assign __unsafe_unretained
retain __strong
  • 属性值一列都是用于声明@property属性声明时用的;
  • 编译器编译后会将这些属性值转换成对应的关键字;
  • 关键字是用于声明属性列表或普通实例变量指针的。

猜你喜欢

转载自blog.csdn.net/qq_33737036/article/details/81370245
今日推荐