基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

@synthesize 和 @dynamic 的作用分别是什么?

知识点图片

在 Objective-C 中,@synthesize@dynamic 是两个用于配合 @property(属性)使用的编译器指令。它们主要控制存取方法(Getter/Setter)的生成方式以及实例变量(Instance Variable / ivar)的处理

简单总结:

  • @synthesize:告诉编译器“帮我生成 Getter/Setter 方法,并关联(或创建)一个实例变量”。
  • @dynamic:告诉编译器“不要生成 Getter/Setter 方法,也不要检查它们是否存在,我会在运行时(Runtime)提供这些方法”。

1. @synthesize (合成)

作用

  1. 生成访问器方法:如果开发者没有手动实现 Getter 和 Setter,编译器会自动生成它们。
  2. 生成/绑定实例变量:它会指定属性对应的实例变量(ivar)。如果没有指定,编译器会自动生成一个。

语法

plaintext
// 将属性 name 绑定到实例变量 _name
@synthesize name = _name; 

现代 Objective-C 的变化 (Autosynthesis)

在 Xcode 4.4 之后,编译器支持自动合成(Autosynthesis)。这意味着你不再需要显式写 @synthesize

  • 如果你声明了一个属性 @property NSString *name;,编译器默认会自动执行 @synthesize name = _name;
  • 它会自动生成 _name 变量和对应的 Getter/Setter。

什么时候还需要手动写 @synthesize

虽然现在很少用,但在以下几种情况编译器不会自动合成,必须手动写:

  1. 同时重写了 Setter 和 Getter:如果你手动实现了属性的所有访问方法(读写属性同时重写了 set/get,只读属性重写了 get),编译器认为你接管了所有控制权,就不会自动生成 ivar。如果你还需要用到 ivar,必须手动 @synthesize
  2. 在 Protocol 中定义的属性:协议里的属性不会自动合成。
  3. 希望指定非默认的 ivar 名称:例如 @synthesize name = myCustomNameVar;

2. @dynamic (动态)

作用

  1. 阻止编译器生成代码:告诉编译器不要自动生成 Getter 和 Setter。
  2. 阻止编译器生成实例变量:它不会创建 _name 这样的成员变量。
  3. 消除编译警告:告诉编译器“虽然你现在在编译时找不到这两个方法,但请放心,程序运行起来的时候会有办法处理的”,从而消除“Method definition not found”的警告。

核心机制

使用 @dynamic 意味着访问该属性时,方法的实现将推迟到运行时(Runtime)决定。通常涉及以下技术:

  • 消息转发(Message Forwarding)
  • 动态方法解析(Dynamic Method Resolution):通过重写 + (BOOL)resolveInstanceMethod:(SEL)sel 在运行时动态添加方法实现。

常见使用场景

  1. Core Data (NSManagedObject)
    这是最常见的场景。Core Data 的属性值存储在数据库中,而不是对象的实例变量里。NSManagedObject 在运行时动态拦截 Getter/Setter 调用来存取数据。因此,Core Data 模型子类的属性通常标记为 @dynamic
  2. 代理/转发
    当一个类想把属性的存取操作转发给另一个对象处理时。

语法

plaintext
@dynamic name;

总结对比表

特性 @synthesize @dynamic
编译器行为 自动生成 Getter/Setter 方法 生成 Getter/Setter 方法
实例变量 (ivar) 自动生成或绑定 ivar (如 _name) 生成 ivar
运行时风险 无(方法编译时已存在) 有(如果运行时没提供方法,程序会 Crash)
主要用途 标准的对象属性存储 Core Data、动态方法解析、消息转发
是否必须写 现代 Obj-C 中通常省略(默认自动合成) 必须显式写出,否则编译器会报错或警告

代码示例

plaintext
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *synthesizedProp;
@property (nonatomic, strong) NSString *dynamicProp;
@end

@implementation MyClass

// 1. @synthesize
// 现代编译器默认会隐含这一行,生成 _synthesizedProp 变量和 get/set 方法
@synthesize synthesizedProp = _synthesizedProp; 

// 2. @dynamic
// 告诉编译器:别管 dynamicProp 的方法,也别生成 _dynamicProp 变量
@dynamic dynamicProp;

- (instancetype)init {
    self = [super init];
    if (self) {
        _synthesizedProp = @"Hello"; // 可以直接访问 ivar
        
        // _dynamicProp = @"World"; // 报错!因为 @dynamic 不会生成 ivar
        
        self.dynamicProp = @"World"; // 编译通过。但如果运行时没处理,会 Crash
    }
    return self;
}

// 对于 @dynamic 属性,通常需要实现动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(setDynamicProp:) || sel == @selector(dynamicProp)) {
        // 在这里动态添加方法实现...
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

@end
00:00
00:00