Item 6 Objective-c 属性的理解

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

图2.1 类内存偏移

老的类定义可能存在于库中,如果连接的代码使用新的类定义,运行时就会出现不相容性。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中使用

图 2.2 不懂原文

这一段我还不理解,欢迎高人指点👈🏿

总结

  1. @property提供了一种定义对象如何封装数据的方法
  2. 使用attributes来指明数据合理存储的方法
  3. 保证设置属性的值时遵守声明的语法
  4. 在iOS中使用nonatomic,使用atomic会影响性能
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容