经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
52个有效方法(7) - 在对象内部尽量直接访问实例变量 - heil-shikaiming
来源:cnblogs  作者:heil-shikaiming  时间:2019/10/16 11:58:00  对本文有异议

在对象内部尽量直接访问实例变量

在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。

  • _name = @"Jack"不经过setter的消息发送,直接为变量赋值,速度快。
    对于以下的 name 属性:@property (nonatomic, copy) NSString *name;
    直接赋值是:_name = @"Jack"; ,通过 self.name = @"Jack"其实等同于_name = @"Jack".copy
  • self.name = @"Jack" 会触发KVO,_name = @"Jack"不会
    -self.name = @"Jack" 可以在 setter 方法中进行断点调试,每次赋值你都知道。
  • 所以有一种合理折中方案就是,读取数据的时候用 NSString *str = _name,赋值用 self.name = @"Jack"

在对象内部访问实例变量时,是通过属性(self.proper)来访问还是通过_proper来访问区别在于是否执行属性的settergetter方法。

  • 如果执行属性的settergetter方法,则通过_proper来访问。

  • 如果未执行属性的settergetter方法,则通过属性(self.proper)来访问。
  1. @interface Wrestler : NSObject
  2. @property (copy, nonatomic) NSString *name; // 将name声明为属性
  3. - (void)smell;
  4. @end
  5. @implementation Wrestler
  6. @synthesize name = _name; // 属性name可以使用实例变量_name直接访问
  7. - (void)setName:(NSString *)aName {
  8. NSLog(@"Set name");
  9. _name = [aName copy];
  10. }
  11. - (NSString *)name {
  12. NSLog(@"Get name");
  13. return [_name copy];
  14. }
  15. - (void)smell {
  16. NSLog(@"*** Smelling ***");
  17. // 使用dot syntax访问实例变量
  18. NSLog(@"%@", self.name);
  19. // 直接调用属性的getter方法
  20. NSLog(@"%@", [self name]);

在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据。

  • 子类可能复写setter方法,用 self.proper = @""可能不等同于_proper = @"".copy

  • 我们写一个Wrestler的子类Cena,该类继承了属性name并重写了其setter方法,该方法会先检验名字后缀是否为Cena,否则抛出异常。
  1. @interface Cena : Wrestler
  2. - (instancetype)initWithName:(NSString *)aName;
  3. - (void)wrestle;
  4. @end
  5. @implementation Cena
  6. @synthesize name = _name;
  7. - (instancetype)initWithName:(NSString *)aName {
  8. self = [super init];
  9. if (self) {
  10. NSLog(@"self.name = aName");
  11. self.name = aName;
  12. }
  13. return self;
  14. }
  15. - (void)wrestle {
  16. NSLog(@"I'm %@, U can't see me", self.name);
  17. }
  18. - (void)setName:(NSString *)aName {
  19. if (![aName hasSuffix:@"Cena"]) {
  20. [NSException raise:NSInvalidArgumentException format:@"last name must be Cena"];
  21. }
  22. _name = [aName copy];
  23. }
  24. @end
  • 在父类Wrestler的init方法中将name初始化为空白字符串@""
  1. (instancetype)init {
  2. self = [super init];
  3. if (self) {
  4. NSLog(@"self.name = empty string");
  5. self.name = @"";
  6. }
  7. return self;
  • 调用
  1. Cena *cena = [[Cena alloc] initWithName:@"John Cena"];
  2. [cena wrestle];
  • 运行崩溃。原因:self.name = @"";。调用子类中覆写的namesetter方法,空白字符串明显没有@"Cena"后缀,从而抛出异常。

使用Lazy Initialization配置的数据,应该通过属性来读取数据。

  1. @property (strong, nonatomic) NSNumber *chamCount;
  2. - (NSNumber *)chamCount {
  3. if (!_chamCount) {
  4. _chamCount = @13;
  5. }
  6. return _chamCount;

不要在setter/getter方法中调用setter/getter方法

  • 将上面的setter方法修改:
  1. - (void)setName:(NSString *)aName {
  2. NSLog(@"Set name");
  3. // _name = [aName copy];
  4. self.name = aName;
  5. }
  • 运行程序,控制台不停输出Set name,崩溃。
  • 原因:setter方法中调用setter方法会不断嵌套调用,最终导致程序崩溃。getter方法同理。

要点

  1. 在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。

  2. 在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据。

  3. 使用Lazy Initialization配置的数据,应该通过属性来读取数据。

  4. 不要在setter/getter方法中调用setter/getter方法。

原文链接:http://www.cnblogs.com/shikaiming/p/11681013.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号