《Effective Objective-C 2.0》- 6:通过属性在对象内部访问实例变量

一. 存取方法

  1. 在设置完属性后,编译器会自动写出一套存取方法,用于访问相应名称的变量:
@interface EOCPerson : NSObject

@property NSString *firstName;
@property NSString *lastName;
@end

 // Same as:

@interface EOCPerson : NSObject

- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;

@end

访问属性,可以使用点语法。编译器会把点语法转换为对存取方法的调用

区分“通过属性访问”与“直接访问”

// 通过属性访问:
self.firstName
// 直接访问:
_firstName
  1. 在对象内部访问实例变量应该怎么做?

(1) 在写入实例变量时,通过其“set方法”来做

self.firstName =  @"aaa";
self.lastName =  @"bbb";

(2) 在读取实例变量时,则直接访问它

NSLog(@"全名是 = %@", [NSString stringWithFormat:@"%@, %@",    _firstName, _lastName]);
// set方法
aPerson.firstName = @"Bob"; // Same as:
[aPerson setFirstName:@"Bob"];

// get方法
NSString *lastName = aPerson.lastName; // Same as:
NSString *lastName = [aPerson lastName];

3.具体使用时需要注意的
(1) 不要在setter方法中调用setter方法

- (void)setName:(NSString *)name {  
    _name = [name copy];  // 正确写法
    self.name = name;     // 会报错
}  

(2) 不要在init和dealloc方法中调用setter/getter方法

- (instancetype)init {  
    self = [super init];  

    if (self) {  

        self.name = @"";  // 会报错
        _name = @"";      // 正确写法
    }        
    return self;  
}

(3) 在惰性初始化中必须通过getter方法访问属性

- (NSNumber *)gameCount {  
    if (!_gameCount) {  
        _gameCount = @13;  
    }  
    return _gameCount;  
} 
NSLog(@"玩游戏的次数 = %d", [_gameCount integerValue]);   // nil ,错误写法,属行未初始化
NSLog(@"玩游戏的次数 = %d", [self.gameCount integerValue]);  // 13 ,正确写法
  1. @synthesize
    然而属性还有更多优势。如果使用了属性的话,那么编译器就会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译器在编译期执行,所以编译器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名称前面加下划线,以此作为实例变量的名字。在前例中,会生成两个实例变量,其名称分别为_firstName 与 _lastName。也可以在类中实现代码里通过@ synthesize语法来指定实例变量的名字:
@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end

前述语法会将生成的实例变量命名为 _myFirstName 与 _myLastName,而不再使用默认的名字 _firstName 与 _lastName。一般情况下无需修改默认的实例变量名,但是如果你不喜欢以下划线来命名实例变量,那么可以用这个方法将其改为自己想要的名字。

若不想令编译器自动合成存取方法,则可以自己实现。如果你只实现了其中一个存取方法,那么另外一个还是会由编译器来合成。还有一种方法能阻止编译器自动合成存取方法,就是使用@dynamic关键字,他会告诉编译器:不要自动创建实现属性所用的实例变量,也不要为其创建存取方法。而且在编译访问属性的代码时,即使编译器发现没有定义存取方法,也不会报错,它相信这些方法能在运行期找到。比方说:从CoreData框架中的NSManagedObject类里继承了一个子类,那么就需要在运行期动态创建存取方法。继承NSManagedObject时之所以要这样做,是因为子类的某些属性不是实例变量,其数据来自后端的数据库中。例如:

@interface EOCPerson : NSManagedObject
@property NSString *firstName;
@property NSString *lastName;
@end

@implementation EOCPerson 
@dynamic firstName, lastName;
@end

编译器不会为上面这个类自动合成存取方法或实例变量。如果用代码访问其中的属性,编译器也不会发出警示信息。

二. 属性特质

定义属性的时候,通常会赋予它一些特性,来满足一些对类保存数据所要遵循的需求。

@property (nonatomic, readwrite, copy) NSString *firstName;

原子性:

  • nonatomic:不使用同步锁
  • atomic:加同步锁,确保其原子性

读写

  • readwrite:同时存在存取方法
  • readonly:只有获取方法

内存管理

  • assign:纯量类型(scalar type)的简单赋值操作
  • strong:拥有关系保留新值,释放旧值,再设置新值
  • weak:非拥有关系(nonowning relationship),属性所指的对象遭到摧毁时,属性也会清空
  • unsafe_unretained :类似assign,适用于对象类型,非拥有关系,属性所指的对象遭到摧毁时,属性不会清空。
  • copy:不保留新值,而是将其拷贝

注意:遵循属性定义

如果属性定义为copy,那么在非设置方法里设定属性的时候,也要遵循copy的语义

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName {
         if (self = [super init]) {
            _firstName = [firstName copy];
            _lastName = [lastName copy];
        }
       return self;
}

要点:

  • 可以用@property语法来定义对象中所封装的数据。
  • 通过"特质"来指定存储数据所需要的正确语义。
  • 在设置属性所对应的实例变量时,一定要遵循该属性所声明的语义。
  • 开发iOS程序时应该使用nonatomic属性,因为atomic属性会严重影响性能。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,396评论 8 265
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,107评论 1 32
  • 桥,白天他属于车 负重又繁忙 到了夜晚 他才有了色彩和温度 夜晚的桥啊 他...
    墨墨入微阅读 196评论 0 0
  • 2017年8月14日 18:32分 不知道怎么回事,脑子里老是想到这些,既然这样写出来算了,这样就不会在想了。 太...
    道道樱木花道阅读 812评论 0 0
  • Py2和Py3的差别 1.在Py3中,range的实现方式是生成器(节省内存),对应Py2中的为xrange。2....
    爱跑步的coder阅读 284评论 2 1