Objective属性properties介绍

对象的属性是给其它对象访问的,属性可以在其它事物中改变。但是,作为一个良好的oop程序,对象的内部属性是不能直接访问的。取方法(getter, setter)被用作对象的基础数据交互的抽象。

一张图了解Objective-C的对象属性
@property(属性指令)可以方便的自动创建和配置属性的访问方法。它允许我们在语义层定义一些公开的属性,它能够在需求自动在实现中生成一些列代码。
属性模块,可以让我们很方便的定义getter、setter行为。一些参数可以决定属性的内存处理方式,所以这块会涉及到Objective-C的内存管理。更多细节可以参阅Objective-C内存管理

@property指令

首先让我们了解一下@property的运作流程,为了方便,我们定一了一个简单的Car类。

//Car.h
#import <Foundation/Foundation.h>
@interface Car: NSObject
@property BOOL running;
@end
`</pre>
<pre>`#import "Car.h"
@implementation Card
@synthesize runing = _runing;
@end
`</pre>
代码编译之后会生成一个runing属性。默认情况下,属性本身命名的方法是一个getter,而带set前缀的则是一个setter,同时,带下划线的是它的实例变量(intance variable)。代码表现如下:
<pre>`//getter
- (BOOL)running {
    return _running;
}

//setter
- (void)setRunning:(BOOL)newValue {
    _runing = newValue;
}
`</pre>
在使用@property定义了属性之后,我们可以通过上面的方法在代码中调用属性。当然,你也可以在实现文件(.m)中去重写它们,以便实现自定义的setter和getter方法。然后,你可能很少会需要这么做,因为@property已经在接口层给你定义好了。
属性可以通过点操作符(.)来进行访问,所以我们可以通过.来存取一个属性!代码表现如下
<pre>`//main.m
#import &lt;Foundation/Foundation.h&gt;
#import "Car.h"

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        Car *bmw = [[Car alloc] init];
        bwm.running = YES; //[bmw setRunning:YES]
        NSLog(@"我的宝马运行状态是%d", bwm.running); //[bmw running]
    }
    return 0;
}
`</pre>
如果需要更改生成的方法的访问属性,可以在@property后的括号指定其属性。

## getter= 和 setter= 属性

如果你不喜欢@property属性默认的命名约定,你也可以getter= / setter= 来更改生成的方法名。比较常见的例子是定义布尔时,我们喜欢使用is前缀。我们可以尝试在声明文件中改变属性声明。代码如下:
<pre>`@property (getter=isRunning) BOOL running;
`</pre>
如此一来,生成的getter / setter现在是isRunning和setRunning了。需要注意的是,公开的属性仍旧是running,你还是可以通过.操作符来调用:
<pre>`Car *bmw = [[Car alloc] init];
bmw.running = YES; //[bmw setRunning:YES]
NSLog(@"Is my BMW running? - %d",bmw.running); //[bmw isRunning]
/**
需要注意的是,这样操作之后,下面的语句是错误的
[bmw running] 因为这个running方法不存在!
*/
`</pre>

## readonly属性

readonly属性是简单的定义只读属性的方法。readonly的方法,没有setter方法,这样下来可以防止通过.操作符进行分配值,但是setter方法不受影响。继续来一个例子。注意:多个property的属性之间,请使用,隔开。
<pre>`#import &lt;Foundation/Foundation.h&gt;
@interface Car : NSObject
@property (getter=isRunning, readonly) BOOL running;
- (void)startEngine;
- (void)stopEngine;
@end
`</pre>
接下来,我们通过startEngine, stopEngine两个方法来改变running属性的值。实现文件如下:
<pre>`//Car.m
#import "Car.h"
@implementation Car
- (void)startEngine {
    _running = YES;
}
- (void)stopEngine {
    _running = NO;
}
@end
`</pre>
需要记住的是,@property属性也给我们定义了一个实例变量,这个实例变量是不需要声明即可调用的。(我们不能使用self.running来设置属性,是因为我们已经给@property定义了readonly属性)接下来,我们就来测试一下新的Car类,以下的代码是Car类的片段:
<pre>`Car *bmw = [[Car aolloc] init];
[bmw startEngine];
NSLog(@"The status of my BMW is %d", bmw.running);
/**
注意:
bmw.running = NO;不在可用!因为@property中存在readonly属性。
*/

截至目前,我们了解了属性的setter和getter,如何修改它们,以及了解了它的一些属性readonly。这些属性并非@property的唯一属性,并且这些属性也可以定义在对象类型的数据上。