面试题答案
一键面试可能出现的内存泄漏场景举例
假设我们有一个简单的命令模式实现,有一个Command
类作为抽象命令类,ConcreteCommand
类继承自Command
,并且ConcreteCommand
类在初始化时需要传入一个接收者对象Receiver
。同时,有一个Invoker
类来调用命令。
// Receiver类
@interface Receiver : NSObject
- (void)action;
@end
@implementation Receiver
- (void)action {
NSLog(@"执行具体操作");
}
@end
// Command抽象类
@interface Command : NSObject
- (void)execute;
@end
// ConcreteCommand类
@interface ConcreteCommand : Command {
Receiver *_receiver;
}
- (instancetype)initWithReceiver:(Receiver *)receiver;
@end
@implementation ConcreteCommand
- (instancetype)initWithReceiver:(Receiver *)receiver {
if (self = [super init]) {
_receiver = receiver;
}
return self;
}
- (void)execute {
[_receiver action];
}
@end
// Invoker类
@interface Invoker : NSObject {
Command *_command;
}
- (void)setCommand:(Command *)command;
- (void)invoke;
@end
@implementation Invoker
- (void)setCommand:(Command *)command {
_command = command;
}
- (void)invoke {
[_command execute];
}
@end
内存泄漏场景:在手动内存管理模式下,如果在Invoker
类中设置了Command
对象后,没有在合适的时机释放该Command
对象(例如在Invoker
类的dealloc
方法中没有释放_command
),就会导致内存泄漏。同样,如果ConcreteCommand
类在持有Receiver
对象时,没有在dealloc
方法中释放_receiver
,也会造成内存泄漏。
使用ARC避免内存泄漏
在ARC环境下,编译器会自动管理对象的内存。例如,上述代码无需开发者手动调用release
等方法。当一个对象的引用计数变为0时,ARC会自动释放该对象。所以在ARC下,只要遵循正常的对象创建和引用规则,上述可能出现的内存泄漏场景就不会发生。
使用手动内存管理避免内存泄漏
- 在
Invoker
类中:在手动内存管理模式下,需要在Invoker
类的dealloc
方法中释放_command
对象。
@implementation Invoker
- (void)dealloc {
[_command release];
[super dealloc];
}
// 其他方法不变
@end
- 在
ConcreteCommand
类中:同样,在ConcreteCommand
类的dealloc
方法中需要释放_receiver
对象。
@implementation ConcreteCommand
- (void)dealloc {
[_receiver release];
[super dealloc];
}
// 其他方法不变
@end
通过在合适的位置释放对象,就可以避免在命令模式实现过程中的内存泄漏问题。