美文网首页
Objective-C属性详解

Objective-C属性详解

作者: fever105 | 来源:发表于2015-09-23 22:43 被阅读279次

    Objective-C属性详解

    理解属性

    谈到属性,人们总是说这个对象的属性指向一个什么对象,把那个属性设置为一个值,等等。这样的说法,让人觉得属性是一个具体的事物,是对象的一部分。

    但是,个人认为,属性其实是一种基于面向对象编程的机制。通过这个机制,我们得以将数据封装在对象内,这里的封装包括存入和获取数据的动作,以及存放的地点

    没错,上面提到的动作和地点分别暗指存取方法实例变量,它们支持着属性机制。两者缺一不可,没有它们,属性机制也就不能正常运行。

    @property指令

    关于@property指令的具体作用,苹果文档也没有一个明确统一的说法。但是经过试验和总结,它有如下主要功能。

    @property NSString *word;为例:

    1. 定义了名为_word的的实例变量。
    2. 声明和实现了名为- (NSString *)word- (void)setWord:的存取方法。

    也就是说,利用@property声明属性,就构建由实例变量和存取方法支持的属性机制。

    实例变量

    作为保存数据的地点,实例变量对于对象来说是不可或缺的。除了使用@property指令自动对其进行定义之外,还可以手动定义实例变量,例如:

    @interface Test : NSObject {
        NSString *_word; // 定义一个实例变量_word
    }
    
    @end
    

    这样定义出来的实例变量同使用@prperty定义的效果完全相同。

    存取方法

    有了保存数据的地点,存放和获取数据的手段也必不可少。除了使用@property自动实现默认的存取方法以外,也可以手动声明和实现存取方法。例如:

    @interface Test : NSObject {
        NSString *_word; // 定义一个实例变量_word
    }
    - (void)setWord:(NSString *)w;
    - (NSString *)word;
    @end
    
    // 以上是interface,以下是implementation 
    
    @implementation Test
    
    // 实现_word的默认存取方法
    - (void)setWord:(NSString *)w
    {
        _word = w;
    }
    
    - (NSString *)word
    {
        return _word;
    }
    @end
    
    
    

    事实上,通过@property所实现的默认存取方法同上面的实现一致。(除了在对属性使用atomic限定词的情况下,稍后会解释)

    架空属性

    上面提到过,属性机制由实例变量和存取方法支持,二者缺一不可。但是,它的灵活之处在于,属性的实例变量和存取方法之间也存在依赖关系:存取方法之中至少有一个必须通过@property自动实现,否则,实例变量将不会被自动定义。也就是说,如果同时手动实现了存取方法(在只读情况下实现了取方法),那么就没有实例变量可用了。例如:

    @interface Test : NSObject 
    
    @property NSString *word;
    
    @end
    
    // 以上是interface,以下是implementation 
    
    @implementation Test
    
    // 实现_word的默认存取方法
    - (void)setWord:(NSString *)w
    {
        _word = w; // 报错
    }
    
    - (NSString *)word
    {
        return _word; // 报错
    }
    @end
    
    

    上面的代码,word的存取方法中引用_word的地方会报错,提示实例变量_word不存在。这时,编译器会认为你想架空属性机制,所以不再自动定义实例变量。

    之所以有这样的设定,是因为通常情况下,默认的属性机制可以满足我们的正常使用;但是,在某些情况下例外,例如一个属性完全依赖于另一个属性,以至于它们存放数据的地点都是同一个,所以,它们共用一个实例变量即可。

    @synthesize指令

    在一些较早的书籍中,经常出现在.h文件中使用@property定义属性,然后在.m文件中使用@synthesize合成属性的情况出现,书上解释为:合成相应属性的实例变量和存取方法。

    但是,截至本文写作之时,利用@property声明属性之后,不论是否使用@synthesize都会自动定义实例变量以及实现存取方法。这样看来,@synthesize的功能稍显多余。

    但是,除了这些重复功能之外,@synthesize还有一些用法,值得注意。

    1. 手动定义实例变量。在同时实现存取方法的情况下,默认实例变量不在自动定义。这时,使用@synthesize可以定义一个可用的实例变量。
    2. 修改实例变量的名称。默认情况下,实例变量的名称是_属性名。通过@synthesize 属性名 = 新实例变量名的形式,可以修改其名称。

    注意@synthesize必须和@property配套使用。例如,如果没有使用@property,而是手动定义了实例变量,再用@synthesize实现存取方法,是不可以的。此时,只能手动实现存取方法。

    属性特性

    属性可以拥有一组特性,用来限定存取方法的行为,写在小括号里。例如:

    @property (nonatomic, readonly, strong) NSString *word;

    有三类:

    1. 多线程特性:atomic / nonatomic。前者可以保证属性在通过多线程存取是不会发生错误。但注意,在使用atomic的情况下,不能再手动生成存取方法,因为它们的实现包含了线程管理的内容。一般都用nonatomic。

    2. 读写特性:readonly / readwrite。前者只允许实现取方法。

    3. 内存管理特性:又分为非ARC模式和ARC模式下。

      • 非ARC
        • retain:限定指针类型的变量,指针所指向的对象的引用计数加1。
        • assign:限定非指针和id类型的变量,不对引用计数进行操作。
        • copy:限定指针类型的变量,复制接收copy消息的对象,并将变量指向这个新的对象。多用于防止可变类型的对象放生改变。
      • ARC
        • strong:作用同非ARC模式下的retain。
        • weak:限定指针类型的变量,作用同非ARC模式下的assign,但是,但变量所指向的对象被释放后,指针自动被设置为nil
        • assign:限定非指针类型的变量,如int,float,结构体等基本数据类型。也可以用关键字unsafe_unretained来表示。

    相关文章

      网友评论

          本文标题:Objective-C属性详解

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