在对象内部尽量直接访问实例变量 --Effictive Objective-C 抄书
来源:互联网 发布:java视频资源百度网盘 编辑:程序博客网 时间:2024/05/17 06:46
在对象之外访问实例变量时,应该总是通过属性来做.在那么在对象内部访问实例变量的时候,又该如何呢?
这是 OCer们一直激烈讨论的问题.有人认为,无论什么情况,都应该通过属性来访问实例变量;也有人说,”通过属性访问”和”直接访问”应该搭配着用. 除了几种特殊情况之外, 笔者强烈建议大家在读取实例变量的时候采用直接访问的形式,而在设置实例变量的时候通过属性来做.
请看下面的类:
@interface EOCPerson : NSObject@property(nonatomic,copy)NSString *firstName;@property(nonatomic,copy)NSString *lastName;//设置全名的快捷方法-(NSString*)fullName;-(void)setFullName:(NSString*)fullName;@end
fullName和 setFullName这两个”便捷方法”,可以这样来实现:
-(NSString*)fullName{ return [NSString stringWithFormat:@"%@ %@",self.firstName,self.lastName];}/** * 下面的方法假设所有的全名有且仅有两部分,当然这个方法也能被改写,来支持外来姓名 */-(void)setFullName:(NSString *)fullName{ NSArray* components = [fullName componentsSeparatedByString:@" "]; self.firstName = [components objectAtIndex:0]; self.lastName = [components objectAtIndex:1];}
在fullName的获取与设置方法中,我们使用”点语法”,通过存储方法来访问相关实例变量. 假设重写这两个方法,不经由存取方法,而是直接访问实例变量:
-(NSString*)fullName{ return [NSString stringWithFormat:@"%@ %@",_firstName,_lastName];}-(void)setFullName:(NSString *)fullName{ NSArray *components = [fullName componentsSeparatedByString:@" "]; _firstName = [components objectAtIndex:0]; _lastName = [components objectAtIndex:1];}
这两种写法有几个区别:
由于不经过 OC的 方法派发( method dispatch ),所以直接访问实例变量的速度当然比较快. 在这种情况下,编译器所生成的代码会直接访问对象实例变量的那块内存.
直接访问实例变量时,不会调用其设置方法. 这就绕过了为相关属性所定义的”内存管理定义”.比如,在ARC下直接访问一个声明为 copy的属性,那么并不会copy该属性,只会保留新值并释放旧值.
如果直接访问实例变量,就不会触发 KVO通知,这样做是否会产生问题,还取决于具体的对象行为.
通过属性来访问有助于排查与之相关的错误,因为可以setter添加断点,监控该属性的调用者以及访问时机.
有一种合理的这种方案,那就是:在写入实例变量时,通过其 setter来做,而在读取实例变量的时候,直接访问之.这样,就技能提高读取操作的速度,又能监控对属性的写入操作.之所以要通过setter来写入实例变量,其首要原因在于,这样做能够确保相关属性的”内存管理定义”得以贯彻.但是,选用这种方法时,需要注意几个问题.
第一个要注意的地方是,在初始化方法中,应该如何设置属性值.这种情况下总是应该直接访问实例变量,因为子类可能会 覆写(override)设置方法.
在上例中,假设EOCPerson有一子类叫做 EOCSmithPerson,这个类表示那些姓 Smith 的人.该子类可能会override lastName所对应的设置方法:
-(void)setLastName:(NSString *)lastName{ if (![lastName isEqualToString:@"Smith"]) { [NSException raise:NSInvalidArgumentException format:@"Last name must be Smith "]; } self.lastName = lastName;}
在父类 EOCPerson的默认初始化方法中,可能会将姓氏设为空字符串.此时若是通过 setter方法来做,那么调用的将是子类的设置方法,从而抛出异常.但是某些情况下有必须在初始化方法中调用该设置方法:如果待初始化的实例变量声明在父类中,而我们又无法在子类中直接访问此实例变量的话,就需要调用 setter 了.
另一个要主要的问题是:懒加载.在这种情况下,必须通过 getter访问属性,否则实例变量就永远不会初始化.比如,EOCPerson类也许会用一个属性来表示人脑中的信息,这个属性所代指的对象相当复杂.由于此属性不常用,而且创建成本较高,所以,我们会在 getter中对其进行懒加载.
-(EOCBrain*)brain{ if(!_brain) { _barin = [Brain new]; } return brain;}
在这种情况下,如果没有使用 getter 方法,而直接访问实例变量,则会看到没有初始化的 brain ,所以说,如果使用了懒加载,就必须通过getter 来访问brain属性.
归纳:
在对象内部读取数据时候,应该通过实例变量来读,而写入数据是,则应该通过属性来写.
在初始化以及 dealloc方法中,总是应该通过实例变量来读写数据
有时会使用懒加载技术配置某些数据,这种情况下,需要通过属性来读取数据.
- 在对象内部尽量直接访问实例变量 --Effictive Objective-C 抄书
- Effetive Objective - C 1.Objective 7.在对象内部尽量直接访问实例变量
- Effective Objective-C 2.0 编写高质量iOS与OS X代码 在对象内部尽量直接访问实例变量
- Effective Objective-C 2.0 第7条:在对象内部尽量访问实例变量
- Effective OC 2.0读书笔记 第7条:在对象内部尽量直接访问实例变量
- Objective-c - 在block内部访问变量
- 类的内部是否应该直接访问实例变量
- Objective-C面向对象-实例变量的访问以及数据封装
- objc直接通过指针访问对象实例变量
- Objective-C----实例变量
- Objective-C定义一个指向函数的指针、直接访问成员变量
- 类和对象:Objective-C概述、面向对象编程、类和对象、实例变量操作
- 访问子类对象实例变量
- Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象,
- day1: Objective-C概述、面向对象编程、类和对象、实例变量操作
- 《Effictive Objective-C 2.0》读书摘要(上)
- 《Effictive Objective-C 2.0》读书摘要(下)
- Objective-c的成员变量访问权限
- android view原理
- mysql 存储过程中变量的定义与赋值操作
- 第四周项目3
- svn下copy项目后定位到新资源库,产生不同版本号的方法
- strcpy的用法、c语言实现、及注意点
- 在对象内部尽量直接访问实例变量 --Effictive Objective-C 抄书
- 机器学习中的常用分布
- 解决JavaScript validator throws NullPointerException in Eclipse问题
- Java操作Redis实现单点故障自动切换
- J2EE规范——JDBC
- MAC下MySQL的安装与使用
- [数据库连接]MySql基础:1
- NGUI简介
- Java使用ProcessBuilder创建子进程出现错误:CreateProcess error=87