MST

星途 面试题库

面试题:Objective-C项目中设计模式应用与内存管理的结合

在一个使用了MVC设计模式的Objective-C iOS应用项目中,视图控制器(ViewController)负责加载网络数据并显示在视图上,模型(Model)对象用于存储数据。请阐述在这种场景下,如何有效地管理内存以避免内存泄漏,特别是当视图控制器频繁创建和销毁时,如何确保模型对象的正确释放以及如何利用设计模式来辅助内存管理,例如是否可以结合单例模式或代理模式来优化内存管理,详细说明实现思路和可能遇到的问题。
44.6万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 视图控制器创建和销毁时的内存管理

  • 避免强引用循环
    • 在视图控制器与模型对象之间,确保引用关系合理。通常视图控制器持有模型对象的强引用是合理的,因为视图控制器负责加载数据到模型。但模型对象不应反向强引用视图控制器,以防止循环引用导致内存泄漏。例如,如果模型对象有一个属性指向视图控制器,应将其声明为weak引用(在Objective - C中)。
    • 在视图控制器与视图之间,视图控制器对视图通常是强引用。但在视图与视图控制器交互时(如按钮点击回调等),视图不应强引用视图控制器,也应使用weak引用。
  • 释放资源
    • 在视图控制器的dealloc方法中,释放所有由视图控制器创建的临时资源,如取消所有正在进行的网络请求。在iOS开发中,可使用NSURLSessiondataTask来进行网络请求,在视图控制器销毁前调用cancel方法取消任务。例如:
@interface ViewController ()
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@end

@implementation ViewController

- (void)dealloc {
    [self.dataTask cancel];
}

@end

2. 模型对象的正确释放

  • 对象生命周期管理
    • 当视图控制器销毁时,由于其对模型对象是强引用,若没有其他对象强引用模型对象,模型对象会随着视图控制器的销毁而被释放。但如果在应用的其他地方有对模型对象的强引用,需要确保在合适的时候释放这些引用,让模型对象能够被正确释放。
    • 例如,如果有一个全局的缓存机制持有模型对象的强引用,在视图控制器销毁时,需要从缓存中移除该模型对象的引用。
  • 自动释放池
    • 如果在加载网络数据过程中创建了大量临时对象,可使用自动释放池来优化内存使用。例如,在解析网络数据并创建模型对象的方法中:
- (void)parseData:(NSData *)data {
    @autoreleasepool {
        // 解析数据并创建模型对象的代码
        // 这里创建的临时对象会在自动释放池结束时被释放
    }
}

3. 结合设计模式优化内存管理

  • 单例模式
    • 实现思路:如果某些模型对象的数据在整个应用中是共享的,且不需要频繁创建和销毁,可以将其设计为单例模式。在Objective - C中实现单例可通过dispatch_once来确保单例对象只被创建一次。例如:
@interface SharedModel : NSObject
@property (nonatomic, strong) NSString *sharedData;
+ (instancetype)sharedInstance;
@end

@implementation SharedModel
+ (instancetype)sharedInstance {
    static SharedModel *sharedModel = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedModel = [[SharedModel alloc] init];
    });
    return sharedModel;
}
@end
  • 可能遇到的问题:单例对象由于其生命周期与应用相同,可能会导致内存占用过高。特别是如果单例对象持有大量数据或资源,在应用长时间运行时可能会影响性能。另外,如果单例对象持有对视图控制器等有生命周期限制对象的强引用,可能会导致这些对象无法被释放,引发内存泄漏。
  • 代理模式
    • 实现思路:在视图控制器与模型对象交互中,可使用代理模式来避免强引用循环。例如,模型对象可以有一个代理属性,当模型数据更新时,通过代理通知视图控制器,而不是直接持有视图控制器的引用。代理属性通常声明为weak,这样模型对象不会阻止视图控制器的释放。
    • 可能遇到的问题:如果代理设置不正确,如没有及时设置或移除代理,可能会导致空指针异常。例如,视图控制器销毁前没有将其在模型对象中的代理设置为nil,模型对象在后续调用代理方法时可能会因为代理对象已被释放而导致程序崩溃。