面试题答案
一键面试键值对存储结构相关内存管理
- 键的选择:
- 不可变对象:尽量使用不可变对象(如NSString、NSNumber等)作为字典的键。因为可变对象在改变时可能会导致哈希值变化,破坏字典的内部存储结构。例如,如果使用可变字符串作为键,在修改字符串后,字典可能无法正确找到对应的键值对,可能会造成数据丢失和潜在的内存泄漏。
- 值的管理:
- 对象所有权:当将对象作为值存储到NSDictionary中时,NSDictionary会对这些对象进行强引用。这意味着只要字典存在,这些对象就不会被释放。例如:
NSString *value = @"Hello"; NSDictionary *dict = @{@"key": value}; // 此时value对象被dict强引用,即使后续没有对value的其他强引用,它也不会被释放
- 避免循环引用:要特别注意避免与其他对象形成循环引用。例如,不要在字典中的值对象内部又强引用字典本身,否则会导致对象无法释放。
对象引用计数相关内存管理
- 自动引用计数(ARC)下:
- ARC机制:在ARC环境下,编译器会自动插入引用计数管理代码。当一个对象被添加到NSDictionary中时,其引用计数会增加。当对象从字典中移除或字典被释放时,对象的引用计数会相应减少。例如:
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary]; NSObject *obj = [[NSObject alloc] init]; [mutableDict setObject:obj forKey:@"objKey"]; // obj的引用计数增加 [mutableDict removeObjectForKey:@"objKey"]; // obj的引用计数减少,如果没有其他强引用,obj会被释放
- 手动引用计数(MRC)下:
- 手动增减引用计数:在MRC环境中,开发者需要手动管理对象的引用计数。当将对象添加到字典中时,要调用
retain
方法增加其引用计数,从字典移除对象时,要调用release
方法减少其引用计数。例如:
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary]; NSObject *obj = [[NSObject alloc] init]; [mutableDict setObject:obj forKey:@"objKey"]; [obj retain]; // 手动增加引用计数 [mutableDict removeObjectForKey:@"objKey"]; [obj release]; // 手动减少引用计数
- 手动增减引用计数:在MRC环境中,开发者需要手动管理对象的引用计数。当将对象添加到字典中时,要调用
优化性能的方法
- 懒加载:
- 延迟创建数据:对于一些不急需的数据,可以采用懒加载的方式。即只有在真正需要使用某个键值对时才创建并添加到字典中,而不是一次性将大量数据全部加载到字典。例如,假设字典中存储的是图片数据,对于暂时不可见的图片,可以延迟加载。
- 分块存储:
- 按功能或类型分块:如果数据具有一定的分类特征,可以将数据分块存储在多个较小的字典中,而不是使用一个大字典。这样在不需要某些数据块时,可以方便地释放对应的字典,减少内存占用。比如,一个应用中有用户信息数据和配置数据,可以分别存储在不同的字典中。
- 使用NSCache替代NSDictionary(部分场景):
- NSCache特点:NSCache是一种自动释放内存的缓存机制。与NSDictionary不同,它不会阻止对象被释放。当系统内存不足时,NSCache会自动释放其存储的对象,有助于避免内存泄漏和优化内存使用。例如,在缓存一些临时数据(如网络请求的临时结果)时,可以使用NSCache。
NSCache *cache = [[NSCache alloc] init]; [cache setObject:data forKey:key];