面试题答案
一键面试确保内存管理正确性及避免循环引用
- 避免循环引用:
- 弱引用:在属性声明时,对于可能产生循环引用的对象,使用
weak
修饰符。例如,在两个对象通过协议进行交互时,如果A对象持有B对象,B对象又通过协议回调持有A对象,B对象中持有A对象的属性应声明为weak
。
@interface B : NSObject @property (nonatomic, weak) id <ProtocolA> aObject; @end
- 无主引用:使用
unowned
修饰符(在ARC下,unowned
类似weak
,但unowned
不会自动置为nil
,使用时要确保对象存在,否则可能导致野指针)。例如:
@interface B : NSObject @property (nonatomic, unowned) id <ProtocolA> aObject; @end
- 弱引用:在属性声明时,对于可能产生循环引用的对象,使用
- 内存管理规范:
- 遵循引用计数原则:在手动内存管理(MRC)下,要确保正确的
retain
、release
和autorelease
调用。在ARC下,编译器会自动处理引用计数,但仍需注意对象的生命周期,避免提前释放或过度保留。 - 对象生命周期控制:确保在合适的时机释放对象,比如在对象的
dealloc
方法中清理相关资源,在ARC下,dealloc
方法中主要处理非内存相关资源的释放,如关闭文件描述符等。
- 遵循引用计数原则:在手动内存管理(MRC)下,要确保正确的
运行时动态添加对新协议的遵循
- 实现思路:
- 使用Objective - C的运行时(runtime)机制。在运行时,可以通过
class_addProtocol
函数为类动态添加协议。首先需要获取类的元数据,然后调用class_addProtocol
函数将新协议添加到类中。 - 同时,需要实现协议中的方法。可以通过
class_addMethod
函数动态为类添加方法实现。
- 使用Objective - C的运行时(runtime)机制。在运行时,可以通过
- 示例代码:
#import <objc/runtime.h> // 定义新协议 @protocol NewProtocol <NSObject> - (void)newProtocolMethod; @end @interface MyClass : NSObject @end @implementation MyClass // 动态添加协议方法的实现 void newProtocolMethodIMP(id self, SEL _cmd) { NSLog(@"执行新协议方法"); } + (void)load { Class myClass = [self class]; // 添加协议 class_addProtocol(myClass, @protocol(NewProtocol)); // 添加协议方法实现 class_addMethod(myClass, @selector(newProtocolMethod), (IMP)newProtocolMethodIMP, "v@:"); } @end
运行时检查对象是否支持协议中的某个可选方法
- 实现思路:
- 利用运行时的
class_getInstanceMethod
函数。首先获取对象的类,然后通过class_getInstanceMethod
函数检查类是否实现了协议中的可选方法。 - 也可以使用
respondsToSelector:
方法,该方法在运行时会检查对象是否能响应某个选择器(方法),可以用于检查对象是否支持协议中的可选方法。
- 利用运行时的
- 示例代码:
MyClass *obj = [[MyClass alloc] init]; // 使用class_getInstanceMethod检查 Method method = class_getInstanceMethod([obj class], @selector(newProtocolMethod)); if (method) { NSLog(@"对象支持新协议方法"); } // 使用respondsToSelector:检查 if ([obj respondsToSelector:@selector(newProtocolMethod)]) { NSLog(@"对象支持新协议方法"); }
在运行时检查对象是否支持协议中的可选方法,class_getInstanceMethod
更底层,直接从类的方法列表中查找;respondsToSelector:
相对更便捷,是NSObject的实例方法,会按照继承体系等规则查找方法实现。