Clang 编译器提供了 OC 自动合成属性的功能。如果一个属性没有被声明为 @dynamic 或者开发者没有自定制它的 getter 或者 setter 方法实现。那 Clang 会自动为你合成 getter 和 setter 方法的实现同时生成对应的成员变量,检查 Clang 编译器是否支持自动合成使用__has_feature(objc_default_synthesize_properties) 这个条件判断。举例
#if __has_feature(objc_default_synthesize_properties)
    //support autosynthesis
#else
    //not support
#endif
当编译器不能自动为你合成属性的时候,需要开发者手动进行。其实也可以换个说法,什么时候需要开发者手动 @synthesize。
举个例子,开发中偶尔会遇到这种报错的情况:
@property (nonatomic,strong) NSString *name;
.....
@implementation
- (void)setName:(NSString *)name {
    _name = name; #编译错误:Use of undeclared identifier '_name'; did you mean 'name'?
}
-  (NSString *)name {
    return @"";
}
@end
这个时候需要我们手动的添加一行代码 @synthesize name = _name; 编译错误就会消失。或者你把编译错误的那行去掉,然后使用命令 clang -rewrite-objc main.m 编译原文件,发现生成的对象结构体中并没有 name 对应的成员变量。
接下来就是总结什么场景下需要我们手动添加 @synthesize。
- 就是我们上面 demo展示的这种可读写的属性,但是开发者自定义了getter和setter方法,注意必须是同时复写,如果只复写setter或者getter的话是不会出现问题的。这也是clang编译器不支持的自动合成的场景。
- 只读属性,开发者自定义了 getter方法。
- @dynamic修饰的属性,- @dynamic本质是告诉编译器- setter与- getter方法由开发者自己定义,不自动合成。
- 在协议 @protocol中声明的属性。
- 在类别 @category中声明的属性。这是因为类别不支持自动添加成员变量,需要手动进行引用关联。
- 如果你复写了父类的属性,你也需要显式地添加 @synthesize
- 如果你想手动修改成员变量名的话,可以使用 @synthesize修改,比如默认成员变量名是_name使用@synthesize name = yname;修改成员变量名为yname,但是不建议这么做。
2018-03-23
补充一些关于第 6 点的说明。
如果父类自动生成属性成员变量和 getter, setter 方法。子类对父类的属性重新进行了 @synthesize 那将会生成新的实例变量。
@interface Fan : NSObject
@property (nonatomic, strong) NSString *name;
@end
//父类 Fan 并没有 @synthesize 而且没有复写 getter 和 setter 方法.
......
@interface FanSub : Fan
@property (nonatomic, strong) NSString *name;
....
@implementation FanSub
@synthesize name = fname;
- (void)setName:(NSString *)name {
    fname = name;
}
- (NSString *)name {
    return fname;
}
@end
注意的是此时子类中的 name 属性对应的实例变量其实是 fname. 即它自己生成的实例变量,而不是父类的 _name 了。可以通过查看编译后的选项来验证 clang -rewrite-objc main.m。结合编译后对应的结构体看一下,确实是成员变量发生了变化。所以这个时候要注意,不能把子类的属性成员变量和父类的成员变量混为一谈。
//编译后的结构体.
struct Fan_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	NSString *_name;
};
struct FanSub_IMPL {
	struct Fan_IMPL Fan_IVARS;
	NSString *fname;
};
一点总结:

所以子类合成和使用属性对应自动变量的两个原则:
- 不允许合成和父类名字一样自动变量
- 如果在子类中有用到父类属性对应的成动变量,则需要显式地在父类头文件的成员变量区域去进行自动变量的声明。
# 一些 QA
Q:@synthesize 合成实例变量的规则是什么?假如 property 名为 foo,存在一个名为_foo 的实例变量,那么还会自动合成新变量么? A: 默认合成带属性名字前面带下划线的成员变量。如果这个下划线的成员变量已经存在,就不会合成新的成员变量了。即上面问题答案是不会合成新的成员变量了。
#参考地址#