MST

星途 面试题库

面试题:Objective-C设计模式与代码规范结合问题

根据《Objective-C代码规范与最佳实践》,在一个复杂的iOS项目中,使用单例模式时,怎样遵循代码规范来保证线程安全,并且在实现单例时,如何符合最佳实践,比如怎样防止多次实例化以及合理处理内存管理?
42.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

保证线程安全

  1. 使用dispatch_once:在Objective-C中,dispatch_once是保证单例线程安全的常用方法。dispatch_once会确保代码块只被执行一次,无论有多少线程同时调用。示例代码如下:
+ (instancetype)sharedInstance {
    static MySingleton *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}
  1. 加锁机制:虽然dispatch_once是更推荐的方式,但也可以使用锁来实现线程安全。例如使用@synchronized关键字:
+ (instancetype)sharedInstance {
    static MySingleton *sharedInstance = nil;
    @synchronized(self) {
        if (!sharedInstance) {
            sharedInstance = [[self alloc] init];
        }
    }
    return sharedInstance;
}

不过@synchronized相对dispatch_once性能会稍差,因为每次访问都需要加锁解锁。

防止多次实例化

  1. 重写allocWithZone::为了防止通过allocinit方法多次实例化单例,需要重写allocWithZone:方法,确保始终返回同一个实例。
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}
  1. 防止拷贝:如果单例对象可能会被拷贝,还需要重写copyWithZone:mutableCopyWithZone:方法,防止创建新的实例。
- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return self;
}

内存管理

  1. ARC环境:在ARC(自动引用计数)环境下,单例对象的内存管理相对简单,因为ARC会自动处理对象的引用计数。只要单例对象有强引用存在(通常在整个应用程序生命周期内都会有对单例的强引用),它就不会被释放。
  2. MRC环境:在MRC(手动引用计数)环境下,需要注意单例对象的引用计数。由于单例对象在应用程序中通常是全局存在的,不需要手动释放它,除非在应用程序退出时明确需要释放资源。可以在单例类中添加一个类方法来释放单例实例(比如+ (void)releaseSharedInstance),在应用程序即将退出时调用。不过这种情况比较少见,因为单例在应用程序生命周期内通常是持续存在的。同时,重写retainreleaseautoreleaseretainCount方法,确保单例的引用计数行为符合预期。
- (instancetype)retain {
    return self;
}

- (oneway void)release {
    // 不执行任何操作,单例不应被释放
}

- (instancetype)autorelease {
    return self;
}

- (NSUInteger)retainCount {
    return NSUIntegerMax;
}