OC实例变量与属性的访问控制

对于刚入门OC开发的人都有一个疑惑,就是下面这些方式创建实例变量有什么区别呢?PS:为了简化,这里省略了property的修饰词。

@interface Person : NSObject {
    @public int a;
    @protected int b;
    @private int c;
}

@property int d;

2,3,4行创建的是实例变量,或成员变量。对C还有印象的都知道结构体吧,OC的类本质上就是一个结构体。
第7行声明的是一个property,直译为属性。它与实例变量是有区别的。

  • 面向对象的封特性

存取一个对象的成员变量时,我们应该使用setter和getter方法,而不是直接引用对象的成员变量。

@interface SomeClass : NSObject
- (void)setName:(NSString *)name;
- (NSString *)name;
@end

@implementation SomeClass {
    NSString *_privateName;
}

- (void)setName:(NSString *)name {
    self->_privateName = name;
}

- (NSString *)name {
    return self->_privateName;
}

@end

这是一个简单的类,该类有一个私有的_privateName实例变量写在@implementation里面,这个实例变量只能在内部使用,外部无法引用。为了让外部能存取这个实例变量,@interface里分别写了getter和setter方法,外部通过这两个方法来访问对象的实例变量。这是一种基本的面向对象设计方式。

但是每次添加一个实例变量都要为它们创建对应的setter和getter,无疑会添加大量的工作量,所以苹果工程师在后续的xcode里添加一些语法支持来降低输入量,这就是property的作用。

@interface SomeClass : NSObject
@property NSString *name;
@end

@implementation SomeClass
@end

可以看到的是,这里一行就可以搞定了。简单来说声明一个property为我们省下了自行添加实例变量和添加setter和getter的时间。值得注意的是,添加property后,系统会自动生成对应的实例变量,该实例变量的名字是property名字前加下划线,如_name

与property相关的是点语法。

  SomeClass *a = [SomeClass new];
  a.name = @"just a";
  NSString *name = a.name;

点语法并不如外表那样看上去那么简单,它可以被展开的。

  [a setName:@"just a"];
  NSString *name = [a name];

这两个方法是不是很熟识了?上面已经说过了,是setter和getter,点语法是将它们简化了。

  • 实例变量的访问控制

上面的例子里提到在@implementation里声明的实例变量是只能在内部访问的,是私有的。另外这种声明是不能被子类引用的。

实例变量有三种常见的访问修饰词

  • @public, 这个声明的实例变量可以在任何地方访问。
  • @protected,系统默认的,当没有指定时会默认这个。不能被外部访问,但能被子类访问。
  • @private,完全私有,这个就等同与声明在@implementation里。

很久很久以前,程序员都习惯在@interface里声明所有实例变量,并为其添加访问控制。那时到底基于什么原因这样写呢?我也搞不清楚,因为太远了。

对于现在来说,好的习惯是在类的@interface里声明必要的property,保持接口文件的可阅读性。

你可能感兴趣的:(OC实例变量与属性的访问控制)