美文网首页
34章 属性

34章 属性

作者: 帽子和五朵玫瑰 | 来源:发表于2018-06-08 09:23 被阅读0次

    34 属性

    34.1属性的特性

    存取类型

    任何一个属性可以声明为readwrite或readonly。默认为readwrite。

    生命周期类型

    (lifetime specifier)的特性包括,unsafe_unretained,assign,strong,weak,copy。这些特性决定了存方法将如何处理与其相关的内存管理问题

    assign是默认的也是最简单的:存方法会将传入的值直接赋给实例变量。以下面这段声明及定义为例:

    @property (assign) int averageScore;
    //等同与@property  int averageScore;
    

    这段代码等同于实现了以下存方法:

    - (void)setAverageScore: (int)d {
        averageScore = d;
    }
    

    copy

    copy特性要求拷贝传入的对象,并将新对象赋给实例变量。以下面这段声明及定义lastName的代码为例

    @property (copy) NSString *lastName;
    //以上方法等同于你下代码
    - (void)setLastName :(NSString *)d{
        lastName = [d copy];
    }
    

    有些类会有特定的子类,这些子类是可修改的,这种类型的对象最适合使用copy特性。比如NSString,就有名为NSMutableString的子类。而向setLastName:方法传入NSMutableString对象是有效的。

    NSMutableString *x = [[NSMutableString alloc] initWithString:@"Ono"];
    //将新创建的对象传入setLastName
    [myObj setLastName:x];
    //因为setLastName方法会拷贝传入对象,所以修改x不会对实例变量产生影响。
    [x appendString:@"Lennon"];
    

    如果传入的对象不是可修改的:NSObject的copy方法其实仅仅是调用copyWithZone,并将nil作为实参传入,不可修改的类通常会被覆盖copyWithZone方法,以优化拷贝过程,以NSString为例,她的copyWithZone方法的示例代码如下:

    - (id)copyWithZone:(NSZone *)z {
        return self;
    }
    

    也就是说,NSString对象不会真的拷贝出一个新对象。

    有些类会有两个版本:一个是可修改的,一个是不可修改的,无论是哪个版本,copy方法都会返回不可修改的版本,例如NSMutableString的copy方法会返回NSString实例,如果要拷贝出可修改对象,就要使用mutableCopy

    Objective-C没有为属性提供mutableCopy这样的特性,如果某个存方法需要赋值传入的对象,并且要求新对象是可修改的,就必须自己编写代码实现(向传入的对象发送mutableCopy消息),而不能依赖属性机制,例如,可以为BNEOwnedAppliance编写出如下的自定义方法setOwnerNames:

    - (void)setOwnerNamesInternal:(NSSet *)newNames {
        _ownerNamesInternal = [newNames mutableCopy];
    }
    

    再谈对象拷贝

    大多数不是来自苹果公司的Objective-C类并没有实现copyWithZone方法

    NSObject类的copy方法和mutableCopy方法的实现代码大致如下:

    - (id)copy {
        return [self copyWithZone:NULL];
    }
    
    -(id)mutableCopy {
        return [self mutableCopyWithZone:NULL];
    }
    

    因此,如果编译以下这段代码

    BNRAppliance *b = [[Appliance alloc] init];
    BNRAppliance *c = [b copy];
    //编译器会报如下错误
    -[BNRAppliance copyWithZone:]: unrecognized seletor sent to instance xxxxxxx
    

    copyWithZone:方法以及mutableCopyWithZone:方法分别在NSCoping与NSMutableCoping协议中进行了声明。这两个协议,大部分FOundation框架的类都至少符合一个。

    atomic与nonatomic

    属性默认是atomic。所以必须显式添加nonatomic。

    34.2实现存取方法

    编译器会默认认为你声明的所有属性合成存取方法。通常来说,实现存取方法很简单,因此很适合交给编译器来做

    有时候,你需要使用存取方法来处理一些特殊逻辑,这种情况下,就需要自己实现存取方法

    1.修改实例变量时,需要更新app的用户界面

    2.修改实例变量时,需要更新一些缓存信息

    例如,你在头文件中声明了一个属性

    @property (nonatomic, copy) NSString *currentState;
    

    当对象调用setCurrentState:方法的时候,你希望这个方法还能实现其他的

    - (void) setCurrentState:(NSString *)currentState {
        _currentState = [currentState copy];
    
        //更新用户界面
        ······
    }
    

    如果你声明一个属性,手动实现存取方法,编译器就不会合成实例变量。

    但如果你需要实例变量,就必须自己创建,创建的方法是在类的实现文件中添加@synthesize指令。代码如下:

    @interface Badger : NSObject ()
    @property (nonatomic) Mushroom *mushroom;
    @end
    @implementation Badger 
    
    @synthesize mushroom = _mushroom;
    
    - (Mushroom *)mushroom {
        return _mushroom;
    }
    
    -(void)setMushroom: (Mushroom *)mush {
        _mushroom = mush;
    }
    

    @synthesize指令会告诉编译器有一个叫做_mushroom的实例变量,它是mushroom以及setMushroom的实例变量。如果它不存在,就要将它创建出来。

    相关文章

      网友评论

          本文标题:34章 属性

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