面试题答案
一键面试类的继承体系影响
- 类别(Category):不影响类的继承体系,只是为已存在的类添加新的方法。例如,给系统类
NSString
添加类别NSString+Custom
来添加自定义方法:
@interface NSString (Custom)
- (NSString *)customAppendString:(NSString *)string;
@end
@implementation NSString (Custom)
- (NSString *)customAppendString:(NSString *)string {
return [self stringByAppendingString:string];
}
@end
所有NSString
对象及其子类对象都能使用这个新方法,但类别无法添加成员变量。
- 扩展(Extension):同样不改变类的继承体系,它是类的一部分,通常用于声明私有方法和属性。例如:
@interface MyClass ()
@property (nonatomic, strong) NSString *privateProperty;
- (void)privateMethod;
@end
@implementation MyClass
- (void)privateMethod {
// 实现
}
@end
扩展中声明的方法和属性对类及其子类可见。
运行时特性影响
- 类别(Category):在运行时,类别中的方法会被动态添加到类的方法列表中。如果类别和类本身或其他类别有相同方法名,会覆盖原有方法(方法查找顺序中类别方法优先级高)。例如有一个
Person
类,有sayHello
方法,在类别Person+Category
中重写sayHello
方法:
@interface Person : NSObject
- (void)sayHello;
@end
@implementation Person
- (void)sayHello {
NSLog(@"Original Hello");
}
@end
@interface Person (Category)
- (void)sayHello;
@end
@implementation Person (Category)
- (void)sayHello {
NSLog(@"Category Hello");
}
@end
Person
对象调用sayHello
方法时,会执行类别中的实现。
- 扩展(Extension):运行时行为与类本身一致,扩展中声明的方法和属性在编译时就已确定,如同在类的主接口中声明一样。例如上述
MyClass
扩展中的privateMethod
和privateProperty
,在运行时就是类的一部分。
内存管理影响
- 类别(Category):由于不能添加成员变量,所以不存在因类别添加变量带来的内存管理问题。但在使用类别方法时,需遵循常规的内存管理规则,如ARC下自动管理对象生命周期,MRC下手动
retain
、release
等。 - 扩展(Extension):扩展中添加的属性,在ARC下内存管理自动进行,在MRC下需要开发者手动管理其内存。例如扩展中添加的
privateProperty
,在MRC下如果是strong
类型属性,使用完需release
。
避免潜在问题
- 命名冲突:
- 类别:在为类添加类别时,确保方法名唯一,避免与类本身或其他类别方法名冲突。可采用独特的命名前缀,如在为
UIView
添加类别时,方法名以YL_UIView_
开头。 - 扩展:扩展主要用于私有方法和属性,通常不会与外部产生命名冲突。但在多人协作开发时,也应注意避免在扩展中定义与其他开发者可能使用的公共方法同名的方法。
- 类别:在为类添加类别时,确保方法名唯一,避免与类本身或其他类别方法名冲突。可采用独特的命名前缀,如在为
- 内存管理:
- 类别:遵循项目的内存管理策略(ARC或MRC),特别是在使用类别方法返回对象时,确保对象的所有权和生命周期管理正确。
- 扩展:在MRC下,对扩展中添加的属性,要在合适的时机进行
retain
、release
等操作,避免内存泄漏或悬空指针。例如在dealloc
方法中release
扩展中定义的strong
类型属性。