关于对象中属性和实例变量的那点小事
本文主要讲述ios开发中一个很让人迷惑的问题,关于属性和实例变量的理解,这个也是一个长期困扰我的问题,主要就是在进行属性的存取时,什么时候使用点语法,什么时候直接访问实例变量.
- 属性和实例变量的简单理解
- 属性特性
- 两种写法的区别
- 两者的使用场景
- 总结
属性和实例变量的简单理解
属性是在Objective-c 2.0之后引入的,主要是用来封装对象中的数据,属性有很多相关的特性,开发者可以让编译器帮助我们自动编写与属性相关的存取方法,此特性引入了一种新的语法”点语法”,让我们更容易的访问对象中的数据.
下面简单介绍一下实例变量的相关特点,在使用属性之前,对于”属性”的定义,我们可能是这样做的:
@interface Teacher : NSObject
//实例变量
{
NSString *_name; //姓名
NSString *_sex; //性别
NSString *_number; //工号
int _age; //年龄
}
@end
然后接下来,我们手动为实例变量加上存取方法,这里就不具体介绍了,是不是感觉非常麻烦,因此,建议大家都是用属性来存储对象数据.
属性的特性
这里,简单介绍一下属性的相关特性,想必大家都已经非常了解了,这里就不详细介绍了,主要说明一下copy的特性.
也许是我之前没有特别注意这一点,通常情况下,当某个属性是指向其他对象的指针,而且该对象的类有可修改的子类(例如 NSString/NSMutableString或者NSArray/NSMutableArray)是,应该将该属性的内存语义管理特性设置为copy.这也主要是为了防止在可变对象修改之后,对象相关的属性值也发生变化,因此需要拷贝一份.
两种写法的区别
1.由于实例变量的访问不需要经过”方法派发”,直接访问实例变量速度快,这种情况下会直接访问保存对象实例变量的那块内存.
2.直接访问实例变量,不会调用其”设置方法”,这就绕过了相关的语义设置,这样在有些情况下是不安全的(例如声明的copy属性,就不会拷贝该属性,只会保留新值释放旧值).
3.直接访问实例变量,不会触发”键值观测”(KVO),这样在有些具体的对象行为下面,有可能会产生问题.
4.通过属性来访问有助于排查错误,因为可以随时监控该属性的获取方法和设置方法,也可以监控属性的调用者,这个对于排查bug是很有帮助的.
那么什么情况下我们应该使用属性访问,什么情况下直接使用实例变量呢?
两者的使用场景
初始化方法中应该如何使用?
这一点是需要特别注意的,在初始化方法中总是应该直接访问实例变量,主要原因有两点:
1.如果直接使用属性访问,这时候有可能实例变量并没有初始化完成,我们使用属性进行存取,也是基于实例变量的访问实现的,在初始化方法中使用属性是不妥的,因为并不能确定相对应的实例变量是否已经初始化完成.
2.因为子类有可能覆写父类的设置方法,这时候如果在初始化方法中使用设置方法,那么这样父类中就会调用子类的设置方法,有可能会出现问题.
延迟加载的初始化方法调用
例如使用如下的代码,延迟加载来加载person
- (Person *)person{
if (!_person) {
_person = [[Person alloc] init];
}
return _person;
}
在这种情况下,我们就必须使用属性的存取方法来访问person,不然我们不能够得到设置好的person.
比较折中的解决方法
1.建议大家在读取实例变量时采用直接访问的形式,在设置实例变量时通过属性设置,因为对于语义的管理主要体现在设置方法中,所以设置实例变量必须通过属性的设置方法,而读取实例变量时,则不需要语义管理,可以直接访问实例变量,这样也可以加快访问速度.
2.在对象外部访问实例变量,总应该通过属性来完成,然而在对象的内部我们应该怎么去访问呢?建议在对象内部应该尽量去访问实例变量,当然也有特殊的情况,两种方式要合理搭配使用.
总结
关于实例变量和属性的相关用法及使用场景,这里进行了简要说明,希望对大家有所帮助.