Item 6 Objective-c 属性的理解
实例变量通常通过accessor
方法来控制,getter
方法用于读取变量,setter
方法由于设置变量。oc2.0通过property
来自动实现accessor
方法的编写,.
语法也简化了控制数据的语法。
声明一个实例变量,你可能会:
@interface EOCPerson: NSObject{
@public
NSString *_firstName;
NSString *_lastName;
@private
NSString *_someIntenalData;
}
@end
OC中通常不这么声明,这种声明对象在编译时就确定了变量的偏移量就确定了,当你添加一个变量时,问题就出现了:
@interface EOCPerson: NSObject{
@public
NSString *_dateOfBirth;
NSString *_firstName;
NSString *_lastName;
@private
NSString *_someIntenalData;
}
@end
原来指向_firstName
的指针现在指向了_dataOfBirth
老的类定义可能存在于库中,如果连接的代码使用新的类定义,运行时就会出现不相容性。oc使用的方法是把实例变量当作一种特殊的变量,类对象来存储变量的偏移量,在运行时查找偏移量,你甚至可以在运行时给一个类添加实例变量。这就是熟知的nonfragile Application Binary Interface(ABI)
,实例变量同样可以在class-continuation category
(implementation)中定义。
通过对象接口中使用property
来使用标准的accessor
方法,声明property
就相当于声明了指定的类型和名字的accessor
。例如:
@interface EOCPerson:NSObject
@property NSString*firstName;
@property NSString*lastName;
@end
等同与:
@interface EOCPerson:NSObject
-(NSString*)firstName;//getter 同名
-(void)setFirstName:(NSString*)firstName; //setter
-(NSString*)lastName;
-(void)setLastName:(NSString*)lastName;
@end
使用.
就相当于直接使用这些方法:
EOCPerson *aPerson = [EOCPerson new];
aPerson.firstName = @"Bob"; //等同于
[aPerson setFirstName:@"Bob"];
编译器自动帮我们编写了这些方法,这个过程称为autosynthesis
,编译器自动在类中加了俩个变量,变量名在前面添加了_
,也可以修改默认的变量名通过:通常不这么做
@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end;
你也可以通过使用@dynamic
来停止生成这个变量及方法
@implementation EOCPerson
@dynamic firstName, lastName;
@end
Property Attributes
attributes
可以用于控制编译器声明的accessors
,使用三种attributes
:
@property(nonatomic, readwrite, copy) NSString *firstName;
可以四种类型的attribute
来管理accessor
Atomicity
默认的,accessors
包括加锁让它们atomic
,如果指定nonatomic
,就可以不加锁,加锁是位了防止变量被不同的线程在某一时间段被同时访问,也就造成了性能开销。
Read/Write
readwrite
可以使用getter和setter方法
readonly
只能使用getter方法,你可以声明这个属性为readonly 来让外部只读,但是在class-continuation category
(.m文件接口部分)重新声明为readwrite。
Memory-Management
这个只影响setter
方法
assign
简单的赋值操作,一般用于纯量类型scalar type
,如CGFloat
NSInteger
strong
表明属性定义了一种拥有关系,当新值被设置,首先被保留,旧的值被释放掉才设置新的值
weak
定义了一种非拥有关系,当新的值被设置时,没有保留,旧的值也没有释放掉,有点类似assign
,但是当其引用的对象被销毁时会被设置为nil。通常用于block
,delegate
,`NSTimer以解决循环引用带来的内存泄露问题。
unsafe_unretained
用于类型时对象类型,表明非拥有关系(unretained) ,当目标被销毁时不会设置为nil,与weak不同
copy
表明拥有关系类似strong
, 不保留值,复制值,任何可能会改变的对象应该使用copy
, 经常用到的就是NSString*
Method Names
getter=<name>
指定getter
方法名,例如对于UISwitch
类,属性开关的状态这样定义:
@property(nonatomic, getter=isOn)BOOL on;
setter=<name>
指定setter
方法名,通常不怎么用
看一个例子:
@interface EOCPerson :NSMagaedObject
@property(copy) NSString*firstName;
@property(copy) NSString*secondName;
-(id)initWithFirstName:(NSString*)firstName;
lastName:(NSString*) lastName;
@end
在implementation中实现自定义的initializer
时,坚持copy
语义很重要:
-(id)initWithFirstName:(NSString*)firstName;
lastName:(NSString*) lastName
{
if((self=[super init])){
_firstName =[firstName copy];
_lastName = [lastName copy];
}
return self;
}
这里你可能会觉得奇怪为什么不使用属性的setter
方法,不能在init中使用
这一段我还不理解,欢迎高人指点👈🏿
总结
-
@property
提供了一种定义对象如何封装数据的方法 - 使用
attributes
来指明数据合理存储的方法 - 保证设置属性的值时遵守声明的语法
- 在iOS中使用
nonatomic
,使用atomic
会影响性能
网友评论