基础回顾-分类&扩展
一、OC分类category
即有.h又有.m文件,主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法
作用:声明私有方法、分解体积庞大的类文件、把framework的私有方法公开;
当一个类可能过于膨胀的时候,通过分类进行拆分是比较好的做法。
特点:运行时决议、可以为系统类添加分类
运行时决议:编写之后没有附加到宿主类上,运行时通过runtime添加宿主类上面的;
运行期决议的,这一点决定了它为什么不能为已有的类添加新的成员变量,实际上是允许添加属性的
可添加内容:实例方法、类方法、协议、属性(仅生成set,get方法声明没有生成实现方法,因此并没有添加实例变量,可以用runtime的关联对象来实现set、get方法)
/* objc_AssociationPolicy参数使用的策略: OBJC_ASSOCIATION_ASSIGN; // assign策略 OBJC_ASSOCIATION_COPY_NONATOMIC; // copy策略 OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略 OBJC_ASSOCIATION_RETAIN; OBJC_ASSOCIATION_COPY; @param object 表示关联对象,即要为哪个对象关联对象 @param key name 获取被关联对象的索引key @param value 被关联对象 @param policy 关联策略 */ void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) static const char NameKey; @implementation Person (Run) - (void)setName:(NSString *)name { objc_setAssociatedObject(self, &NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (NSString *)name { return objc_getAssociatedObject(self, &NameKey); } @end
注意:分类添加的方法可以覆盖原类的方法;同一个类拥有多个分类的情况下,拥有相同方法的情况下,最后编译的分类中方法生效;名字相同的分类会引起编译报错;
常见。比如给UIColor添加一些跟16进制色值互转的方法。如下:
@interface UIColor (Hex) + (UIColor*) colorWithHex: (NSUInteger) hex; @end @implementation UIColor (Hex) + (UIColor*) colorWithHex: (NSUInteger)hex { CGFloat red, green, blue, alpha; red = ((CGFloat)((hex >> 16) & 0xFF)) / ((CGFloat)0xFF); green = ((CGFloat)((hex >> 8) & 0xFF)) / ((CGFloat)0xFF); blue = ((CGFloat)((hex >> 0) & 0xFF)) / ((CGFloat)0xFF); alpha = hex > 0xFFFFFF ? ((CGFloat)((hex >> 24) & 0xFF)) / ((CGFloat)0xFF) : 1; return [UIColor colorWithRed: red green:green blue:blue alpha:alpha]; } @end
二、OC扩展Extension
只有.h文件;OC扩展可以理解成是匿名的Category,可以用来给当前类添加属性和新方法,不作用在Subclass;
其实可以理解成原有类多了一个.h文件,但写在这个头文件里面的属性、方法等,都是私有的,只能被这个类所拥有访问。
作用:声明私有属性、声明私有方法、声明私有成员变量
特点:编译时决议、只有声明的形式存在,多数情况下寄生宿主类.m中、不能为系统类添加扩展
OC扩展/分类创建方式:
三、Swift扩展 (Swift没有分类概念)
可以给一个现有的类,结构体,枚举,还有协议添加新的功能。它还拥有不需要访问被扩展类型源代码就能完成扩展的能力(即逆向建模)。扩展和 Objective-C 的分类很相似。(与 Objective-C 分类不同的是,Swift 扩展是没有名字的。)
扩展可以给一个类型添加新的功能,但是不能重写已经存在的功能。
扩展可以扩充一个现有的类型,给它添加一个或多个协议
可变实例方法,实例方法标记为 mutating
Swift 中的扩展可以:
-
- 添加计算型实例属性和计算型类属性
- 定义实例方法和类方法
- 提供新的构造器
- 定义下标
- 定义和使用新的嵌套类型
- 使已经存在的类型遵循(conform)一个协议
注意:名字相同的分类会引起编译报错;对一个现有的类型,如果你定义了一个扩展来添加新的功能,那么这个类型的所有实例都可以使用这个新功能,包括那些在扩展定义之前就存在的实例;
扩展可以添加新的计算属性,仅可通过关联对象的方式添加存储属性(不能添加属性观察者),如下
var currentLoadPage: Int{ get { return objc_getAssociatedObject(self, &key) as? Int ?? 0 } set { objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN) } }
语法:
extension SomeType { // 在这里给 SomeType 添加新的功能 } extension SomeType: SomeProtocol, AnotherProtocol { // 协议所需要的实现写在这里 }
1) 扩展可以给现有的类型添加新的构造器。需要确保每个通过该构造器创建的实例都是初始化完整的。
extension Rect { init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }
2)扩展可以给现有类型添加新的实例方法和类方法
extension Int { func repetitions(task: () -> Void) { for _ in 0..<self { task() } } }
3)通过扩展添加的实例方法同样也可以修改(或 mutating(改变))实例本身
extension Int { mutating func square() { self = self * self } } var someInt = 3 someInt.square() // someInt 现在是 9
4)扩展可以给现有的类型添加新的下标
extension Int { subscript(digitIndex: Int) -> Int { var decimalBase = 1 for _ in 0..<digitIndex { decimalBase *= 10 } return (self / decimalBase) % 10 } }
5)扩展可以给现有的类,结构体,还有枚举添加新的嵌套类型
extension Int { enum Kind { case negative, zero, positive } var kind: Kind { switch self { case 0: return .zero case let x where x > 0: return .positive default: return .negative } } }