@synthesize
和 @dynamic
是 Objective-C 中用于控制属性合成的两个关键字,它们的作用和用法有显著区别。以下是它们的详细说明:
1. @synthesize
@synthesize
用于显式声明编译器为属性生成对应的实例变量(ivar)和访问器方法(getter 和 setter)。
作用:
- 告诉编译器自动生成属性的 getter 和 setter 方法。
- 如果未显式指定实例变量名,编译器会生成一个默认的实例变量(通常以下划线
_
开头,例如_propertyName
)。 - 可以自定义实例变量的名称。
语法:
objc
@synthesize propertyName = _instanceVariableName;
示例:
objc
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation MyClass
@synthesize name = _customName; // 自定义实例变量名
@end
-
如果没有显式使用
@synthesize
,编译器会自动生成以下代码:objc@synthesize name = _name;
使用场景:
- 需要自定义实例变量名时。
- 在早期的 Objective-C 版本中(Xcode 4.4 之前),必须显式使用
@synthesize
来生成访问器方法。
2. @dynamic
@dynamic
用于告诉编译器不要为属性生成实例变量和访问器方法,开发者会在运行时动态提供这些方法的实现。
作用:
- 禁止编译器自动生成 getter 和 setter 方法。
- 开发者需要在运行时通过其他方式(如消息转发机制)提供这些方法的实现。
- 常用于 Core Data 或动态方法解析的场景。
语法:
objc
@dynamic propertyName;
示例:
objc
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation MyClass
@dynamic name; // 告诉编译器不要生成 getter 和 setter
// 在运行时动态解析方法
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(setName:) || aSelector == @selector(name)) {
return someOtherObject; // 将方法调用转发给其他对象
}
return [super forwardingTargetForSelector:aSelector];
}
@end
使用场景:
- Core Data :Core Data 会为
NSManagedObject
子类的属性动态生成访问器方法。 - 动态方法解析 :在运行时通过
resolveInstanceMethod:
或消息转发机制动态提供方法实现。 - 桥接其他语言或框架:例如通过桥接方式调用 Swift 或 C 代码。
3. 区别对比
特性 | @synthesize |
@dynamic |
---|---|---|
编译器行为 | 生成 getter 和 setter 方法 | 不生成 getter 和 setter 方法 |
实例变量 | 生成实例变量(可自定义名称) | 不生成实例变量 |
运行时行为 | 直接访问生成的实例变量和方法 | 需要在运行时动态提供方法实现 |
使用场景 | 普通属性、自定义实例变量名 | Core Data、动态方法解析、消息转发 |
默认行为 | 如果没有显式声明,编译器默认生成 | 必须显式声明 |
4. 默认行为
-
在现代 Objective-C 中(Xcode 4.4 及以后),如果没有显式使用
@synthesize
或@dynamic
,编译器会默认生成以下代码:objc@synthesize propertyName = _propertyName;
即自动生成实例变量和访问器方法。
5. 示例对比
使用 @synthesize
objc
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
@synthesize name = _name; // 显式生成实例变量 _name
@end
使用 @dynamic
objc
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
@dynamic name; // 不生成实例变量和访问器方法
// 在运行时动态解析方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(setName:)) {
class_addMethod([self class], sel, (IMP)dynamicSetName, "v@:@");
return YES;
} else if (sel == @selector(name)) {
class_addMethod([self class], sel, (IMP)dynamicGetName, "@@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
// 动态实现的 setter 方法
void dynamicSetName(id self, SEL _cmd, NSString *name) {
// 存储 name 的逻辑
}
// 动态实现的 getter 方法
NSString *dynamicGetName(id self, SEL _cmd) {
// 返回 name 的逻辑
return @"Dynamic Name";
}
@end
6. 总结
@synthesize
:用于显式生成属性的实例变量和访问器方法,适合普通属性或需要自定义实例变量名的场景。@dynamic
:用于禁止编译器生成访问器方法,适合需要在运行时动态提供方法实现的场景(如 Core Data 或消息转发)。