基础回顾-分类&扩展

一、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
        }
    }
}

 

posted @ 2023-02-16 09:56  Belinda_sl  阅读(35)  评论(0编辑  收藏  举报