美文网首页
《Effective Objective-C 2.0》- 6:通

《Effective Objective-C 2.0》- 6:通

作者: WhistleCai | 来源:发表于2018-06-11 15:18 被阅读0次

一. 存取方法

  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属性会严重影响性能。

相关文章

网友评论

      本文标题:《Effective Objective-C 2.0》- 6:通

      本文链接:https://www.haomeiwen.com/subject/lfdwrftx.html