一、点语法的本质是方法的调用,而不是访问成员变量(OC中访问成员变量只能使用->),当使用点语法时编译器会自动展开成相应的方法(编译器特性)。
点语法陷阱(ARC):
1)死循环
- (void)setAge:(int)age { self.age = age; }
分析:self.age = age 实际为赋值调用 set 方法; 会被编译器展开成如下代码,造成了死循环!
- (void)setAge:(int)age { [self setAge:age]; }
正确写法:
- (void)setAge:(int)age { self->_age = age; }
或:
- (void)setAge:(int)age { _age = age; }
说明:age为Person类的属性,在Person.m中我们可以使用 “->”访问私有成员变量 _age;
2)死循环
- (int)age { return self.age; }
此处的 self.age 实际为取值,调用 get 方法,造成死循环。展开如下:
- (int)age { return [self age]; }
分析:此处的self.age,是取值,则会被编译器转为 [self age];即调用了get方法,造成了死循环!
正确写法:
- (int)age { return self->_age; }
或:
- (int)age { return _age; }
二、@property 和 @synthesize 关键字(编译器指令:告诉编译器要做什么)
先说一说为什么使用 @property
// .h @interface Person : NSObject { int _age; } - (void)setAge:(int)age; - (int)age; @end // .m @implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } @end
以上是手动实现的 age 属性的 set/get 方法。
@property 会告诉编译器,声明 age 属性的访问器(set/get)方法,免去我们手工书写的繁琐!
示例:
// .h 声明age属性 @property (nonatomic, assign) int age; // 等同于声明了age属性set和get方法 // 访问器 - (void)setAge:(int)age; - (int)age;
@synthesize 会告诉编译器,生成 age 属性(set/get)的实现!
示例(通用写法):
// 告诉编译器生成 age 属性的访问器,且在访问器里访问 _age 成员变量;如果没有 _age 成员变量,则自动生成@private的_age成员变量(私有的) @synthesize age = _age; // @synthesize 等同于set和get的实现,书写在@implementation……@end 之间 - (void)setAge:(int)age { _age = age; } - (int)age { return _age; }
示例:
// .h @property (nonatomic, assign) int age; @synthesize age = _num; 分析:表示用 age 的 set 和 get 方法,修改 _num 属性变量的值 - (void)setAge:(int)age { _num = age; } - (int)age { return _num; }
示例:
// 默认会访问 age 成员变量,而不是 _age; @synthesize age;
三、Xcode4.4之后,
1)@property增强版。只要:
@property (nonatomic, assign) int age;
好处:系统就会帮我们实现 age 属性的 set/get 方法。
缺点:自动生成的成员变量 _age 是私有的,子类是不能访问的。
如果让子类访问父类的 _age 成员变量,须手动实现 _age 成员变量:
// .h @interface Person : NSObject { int _age; } @property (nonatomic, assign) int age; @end
// Man 继承自 Person @implementation Man - (void)test { // 父类Person,存在 _age 成员属性,则子类就可以使用 _age数形变量 NSLog(@"%d", _age); } @end
2)@property增强下重写 set/get 方法
1)如果手动实现了set方法,那么编译器就只生成get方法和对应的成员变量;
2)如果手动实现了get方法,那么编译器就只生成set方法和对应的成员变量;
3)如果set和get方法都是手动实现的,那么编译器将不会生成成员变量,且报错(Use of undeclared identifier ‘_age’)。
若需要重写 set/get 方法,正确写法:
@synthesize age = _age; - (void)setAge:(int)age { _age = age; } - (int)age { return _age; }
尊重作者劳动成果,转载请注明: 【kingdev】