atomic特质的局限性

发布于:2024-06-11 ⋅ 阅读:(38) ⋅ 点赞:(0)

leading-logo

为什么在实际的 Objective-C 开发中, 几乎所有的属性都声明为 nonatomic ? 声明为 atomic 的属性我是真的没见过

在实际的 Objective-C 开发中,大多数属性通常声明为 nonatomic,主要原因包括性能考虑和常见的设计模式。具体原因如下:

  1. 性能问题

    • atomic 属性的实现会在生成的 getter 和 setter 方法中加入锁机制,以确保操作的原子性。这会导致一定的性能开销,尤其是在高频率访问的场景中,性能损失更为明显。
    • nonatomic 属性的读写操作不需要加锁,因此在性能上比 atomic 更高效,特别是在需要高效数据访问的应用中,如 UI 操作或实时处理。
  2. 并发访问的复杂性

    • 即使将属性声明为 atomic,也只能保证单次读或写操作的原子性。大多数情况下,线程安全问题不仅仅是单次读写操作,而是涉及多个操作的组合。这种情况下,仅依赖 atomic 是不够的。
    • 开发者通常需要更高级的并发控制机制来确保线程安全,如使用锁、队列(GCD)、NSOperationQueue 等。这些机制提供了更细粒度的控制,能够处理更复杂的并发访问场景。
  3. 惯用设计模式

    • 许多 Objective-C 代码库和框架默认使用 nonatomic 属性,因为它们假定开发者会自行处理必要的线程安全控制。
    • 使用 nonatomic 属性可以使代码更加简洁,并且开发者可以根据需要灵活地选择适当的并发控制策略。
  4. UI 相关的属性

    • 在 iOS 开发中,大部分 UI 操作必须在主线程上执行,因此通常不需要 atomic 属性来保证线程安全。UI 相关的属性声明为 nonatomic 更为常见和合理。

示例

以下是一个常见的属性声明为 nonatomic 的例子:

@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger count;
@end

线程安全的实现

为了实现更复杂的线程安全控制,开发者通常会这样做:

  1. 使用锁
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) NSLock *lock;
@end

@implementation MyClass
- (void)setName:(NSString *)name {
    [self.lock lock];
    _name = name;
    [self.lock unlock];
}

- (NSString *)name {
    [self.lock lock];
    NSString *name = _name;
    [self.lock unlock];
    return name;
}
@end
  1. 使用 GCD
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@end

@implementation MyClass
- (instancetype)init {
    self = [super init];
    if (self) {
        _syncQueue = dispatch_queue_create("com.example.MyClassSyncQueue", DISPATCH_QUEUE_SERIAL);
    }
    return self;
}

- (void)setName:(NSString *)name {
    dispatch_sync(self.syncQueue, ^{
        _name = name;
    });
}

- (NSString *)name {
    __block NSString *name;
    dispatch_sync(self.syncQueue, ^{
        name = _name;
    });
    return name;
}
@end

通过这些高级的并发控制机制,开发者可以确保属性的线程安全,而不需要依赖 atomic,同时还能避免其带来的性能损耗。

trailing-logo


网站公告

今日签到

点亮在社区的每一天
去签到