面试题答案
一键面试内存管理方面
- 隐藏属性:
- 通过Extension可以声明私有属性,这些属性不会暴露给外部调用者,在一定程度上保护数据。同时,合理使用这些私有属性可以优化内存管理。例如,假设我们有一个
Person
类,用于管理个人信息,并且可能会在内部有一些临时缓存数据的属性。
// Person.h @interface Person : NSObject @property (nonatomic, copy) NSString *name; @end // Person.m @interface Person () // 私有属性,用于临时缓存一些计算结果,避免重复计算 @property (nonatomic, strong) NSMutableDictionary *tempCache; @end @implementation Person - (void)calculateSomething { if (!self.tempCache) { self.tempCache = [NSMutableDictionary dictionary]; // 填充临时缓存数据 [self.tempCache setObject:@"Some value" forKey:@"key"]; } // 使用临时缓存数据进行计算 } - (void)dealloc { self.tempCache = nil; } @end
- 这样做的好处是,
tempCache
属性不会被外部随意访问和修改,减少了因外部错误操作导致的内存问题。在dealloc
方法中,将tempCache
置为nil
,释放其引用的内存。
- 通过Extension可以声明私有属性,这些属性不会暴露给外部调用者,在一定程度上保护数据。同时,合理使用这些私有属性可以优化内存管理。例如,假设我们有一个
- 方法封装:
- 在Extension中可以定义私有方法,这些方法可以辅助内存管理相关的操作。比如,我们可以在一个图片加载类
ImageLoader
中,通过私有方法来处理图片加载完成后的内存清理等操作。
// ImageLoader.h @interface ImageLoader : NSObject - (void)loadImageFromURL:(NSURL *)url; @end // ImageLoader.m @interface ImageLoader () - (void)_imageLoaded:(UIImage *)image; @end @implementation ImageLoader - (void)loadImageFromURL:(NSURL *)url { // 异步加载图片 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *imageData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; dispatch_async(dispatch_get_main_queue(), ^{ [self _imageLoaded:image]; }); }); } - (void)_imageLoaded:(UIImage *)image { // 在这里可以进行一些图片处理,处理完成后,如果有临时占用的内存可以释放 // 例如,如果处理图片过程中使用了一个大的临时缓存数组 // 处理完成后将其置为nil // 假设这里有一个NSMutableArray *tempArray用于临时存储处理数据 self.tempArray = nil; // 显示图片等操作 } @end
- 在Extension中可以定义私有方法,这些方法可以辅助内存管理相关的操作。比如,我们可以在一个图片加载类
代码结构方面
- 功能分组:
- 对于一个大型项目中的复杂类,通过Extension可以将不同功能的方法进行分组,使代码结构更加清晰。例如,在一个游戏角色类
GameCharacter
中,我们可以把与移动相关的方法放在一个Extension中,把与战斗相关的方法放在另一个Extension中。
// GameCharacter.h @interface GameCharacter : NSObject @property (nonatomic, assign) CGPoint position; @end // GameCharacter+Movement.h @interface GameCharacter (Movement) - (void)moveLeft; - (void)moveRight; - (void)jump; @end // GameCharacter+Movement.m @implementation GameCharacter (Movement) - (void)moveLeft { self.position.x -= 10; } - (void)moveRight { self.position.x += 10; } - (void)jump { self.position.y += 20; } @end // GameCharacter+Combat.h @interface GameCharacter (Combat) - (void)attack; - (void)defend; - (void)useSkill:(NSString *)skillName; @end // GameCharacter+Combat.m @implementation GameCharacter (Combat) - (void)attack { // 攻击逻辑 } - (void)defend { // 防御逻辑 } - (void)useSkill:(NSString *)skillName { // 使用技能逻辑 } @end
- 这样在阅读和维护代码时,可以很方便地找到与特定功能相关的代码,提高代码的可维护性。
- 对于一个大型项目中的复杂类,通过Extension可以将不同功能的方法进行分组,使代码结构更加清晰。例如,在一个游戏角色类
- 遵循协议:
- 当一个类需要遵循多个协议时,使用Extension可以将遵循不同协议的实现分开,使代码结构更有条理。比如,
FileManager
类需要同时遵循NSCopying
协议用于复制操作,遵循NSCoding
协议用于归档和解档操作。
// FileManager.h @interface FileManager : NSObject @property (nonatomic, copy) NSString *fileName; @end // FileManager+Copying.h @interface FileManager (Copying) <NSCopying> @end // FileManager+Copying.m @implementation FileManager (Copying) - (id)copyWithZone:(NSZone *)zone { FileManager *copy = [[[self class] allocWithZone:zone] init]; copy.fileName = [self.fileName copyWithZone:zone]; return copy; } @end // FileManager+Coding.h @interface FileManager (Coding) <NSCoding> @end // FileManager+Coding.m @implementation FileManager (Coding) - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.fileName forKey:@"fileName"]; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { self.fileName = [aDecoder decodeObjectForKey:@"fileName"]; } return self; } @end
- 这种方式使得遵循不同协议的代码实现相互分离,易于理解和维护。
- 当一个类需要遵循多个协议时,使用Extension可以将遵循不同协议的实现分开,使代码结构更有条理。比如,