Category & Extension
首先,Category(类别)和Extension(类扩展)是非正式协议的两种写法,目的都是在无需子类化的情况下,给类添加方法(和属性)。
Swift
在Swift中,已经没有了Category的写法,Extension的写法也更加简洁,功能也更加强大。可以用于:
1、代码模块化区分,层次更清晰
2、缺省实现协议中的方法,相当于协议方法的默认实现
3、定义新的实例方法和类方法,或提供新的初始化方法
4、添加属性:普通情况下只能添加计算属性(可读可写,但无具体值,没有存储功能和意义)
var testInt: Int {
get { return 0 }
set { //doSomething }
}
但特殊情况下,可以利用Runtime动态添加属性(只能是继承于OC的子类或系统类,AnyObject)
注:Swift中利用OC的Runtime特性动态添加属性,含义上和协议中添加属性不太一样,因为协议中的属性目的是为了让外部类是赋值实现,动态添加属性仅仅是为了添加属性。
private var SwiftPropertyNameKey: Void?
protocol AddPropertyProtocol: AnyObject { }
extension AddPropertyProtocol {
var swiftPropertyName: String? {
get { return objc_getAssociatedObject(self, &SwiftPropertyNameKey) as? String }
set { objc_setAssociatedObject(self, &SwiftPropertyNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
}
OC中的非正式协议
类别(Category)
@interface NSString(StringFrame)
- (CGSize *)getStringFrame(labelWidth: CGFloat);
@end
类扩展(Extension)
@interface MyClass() {
float value;
}
- (void)setValue:(float)newValue;
@end
类别和类扩展区别
类别中只能增加方法,类扩展不仅可以增加方法,还可以增加实例变量(默认private,作用范围只在当前类)
类别是在运行时把方法添加到类中(所以不能添加属性,但可以不被实现),类扩展是在编译阶段被添加到类中,不实现编译器会有警告。
.h中的类扩展方法是公有的,.m中是私有的(声明私有方法的标准实现)
类别中添加属性
.h中声明
@interface YourClasseBaseNSObject (Category)
@property(nonatomic, copy) NSString *propertyName; //相当于声明了getter和setter方法
@end
.m中实现(不实现getset运行会因找不到方法而崩溃)
static NSString *propertyNameKey =@"propertyNameKey";
@implementation YourClasseBaseNSObject (Category)
- (void)setPropertyName: (NSString *)propertyName {
objc_setAssociatedObject(self, &propertyNameKey, propertyName, OBJC_ASSOCIATION_COPY);
}
- (NSString *)propertyName {
return objc_getAssociatedObject(self, &propertyNameKey);
}
@end
扩展阅读:https://tech.meituan.com/2015/03/03/diveintocategory.html