NSObject(FWSwizzle)

@interface NSObject (FWSwizzle)

框架NSObject类包装器

实现block必须返回一个block,返回的block将被当成originalSelector的新实现,所以要在内部自己处理对super的调用,以及对当前调用方法的self的class的保护判断(因为如果originalClass的originalSelector是继承自父类的,originalClass内部并没有重写这个方法,则我们这个函数最终重写的其实是父类的originalSelector,所以会产生预期之外的class的影响,例如originalClass传进来UIButton.class,则最终可能会影响到UIView.class)。block的参数里第一个为你要修改的class,也即等同于originalClass,第二个参数为你要修改的selector,也即等同于originalSelector,第三个参数是一个block,用于获取originalSelector原本的实现,由于IMP可以直接当成C函数调用,所以可利用它来实现“调用 super”的效果,但由于originalSelector的参数个数、参数类型、返回值类型,都会影响IMP的调用写法,所以这个调用只能由业务自己写

  • 使用swizzle替换对象实例方法为block实现,identifier相同时仅执行一次。结合fwIsSwizzleMethod使用

    Declaration

    Objective-C

    - (BOOL)fw_swizzleInstanceMethod:(nonnull SEL)originalSelector
                          identifier:(nonnull NSString *)identifier
                           withBlock:
                               (nonnull id _Nonnull (^)(
                                   __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                   IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    originalSelector

    原始方法

    identifier

    唯一标识

    block

    实现句柄

    Return Value

    是否成功

  • 判断对象是否使用swizzle替换过指定identifier实例方法。结合fwSwizzleMethod使用

    Note

    因为实际替换的是类方法,为了防止影响该类其它对象,需先判断该对象是否替换过,仅替换过才执行自定义流程

    Declaration

    Objective-C

    - (BOOL)fw_isSwizzleInstanceMethod:(nonnull SEL)originalSelector
                            identifier:(nonnull NSString *)identifier;

    Parameters

    originalSelector

    原始方法

    identifier

    唯一标识

    Return Value

    是否替换

Runtime

  • 安全调用方法,如果不能响应,则忽略之

    Declaration

    Objective-C

    - (nullable id)fw_invokeMethod:(nonnull SEL)aSelector;

    Parameters

    aSelector

    要执行的方法

    Return Value

    id 方法执行后返回的值。如果无返回值,则为nil

  • 安全调用方法,如果不能响应,则忽略之

    Declaration

    Objective-C

    - (nullable id)fw_invokeMethod:(nonnull SEL)aSelector
                        withObject:(nullable id)object;

    Parameters

    aSelector

    要执行的方法

    object

    传递的方法参数,非id类型可使用桥接,如int a = 1;(__bridge id)(void *)a

    Return Value

    id 方法执行后返回的值。如果无返回值,则为nil

  • 安全调用方法,支持多个参数

    Declaration

    Objective-C

    - (nullable id)fw_invokeMethod:(nonnull SEL)aSelector
                       withObjects:(nonnull NSArray *)objects;

    Parameters

    aSelector

    要执行的方法

    objects

    传递的参数数组

    Return Value

    id 方法执行后返回的值。如果无返回值,则为nil

  • 对super发送消息

    Declaration

    Objective-C

    - (nullable id)fw_invokeSuperMethod:(nonnull SEL)aSelector;

    Parameters

    aSelector

    要执行的方法,需返回id类型

    Return Value

    id 方法执行后返回的值

  • 对super发送消息,可传递参数

    Declaration

    Objective-C

    - (nullable id)fw_invokeSuperMethod:(nonnull SEL)aSelector
                             withObject:(nullable id)object;

    Parameters

    aSelector

    要执行的方法,需返回id类型

    object

    传递的方法参数

    Return Value

    id 方法执行后返回的值

  • 安全调用内部属性获取方法,如果属性不存在,则忽略之

    Note

    如果iOS13系统UIView调用部分valueForKey:方法闪退,且没有好的替代方案,可尝试调用此方法

    Declaration

    Objective-C

    - (nullable id)fw_invokeGetter:(nonnull NSString *)name;

    Parameters

    name

    内部属性名称

    Return Value

    属性值

  • 安全调用内部属性设置方法,如果属性不存在,则忽略之

    Note

    如果iOS13系统UIView调用部分valueForKey:方法闪退,且没有好的替代方案,可尝试调用此方法

    Declaration

    Objective-C

    - (nullable id)fw_invokeSetter:(nonnull NSString *)name
                        withObject:(nullable id)object;

    Parameters

    name

    内部属性名称

    object

    传递的方法参数

    Return Value

    方法执行后返回的值

Property

  • 临时对象,强引用,支持KVO

    Note

    备注:key的几种形式的声明和使用,下同
    1. 声明:static char kAssociatedObjectKey; 使用:&kAssociatedObjectKey
    2. 声明:static void *kAssociatedObjectKey = &kAssociatedObjectKey; 使用:kAssociatedObjectKey
    3. 声明和使用直接用getter方法的selector,如@selector(xxx)、_cmd
    4. 声明和使用直接用c字符串,如"kAssociatedObjectKey"

    Declaration

    Objective-C

    @property (nonatomic, strong, nullable) id fw_tempObject;
  • 读取关联属性

    Declaration

    Objective-C

    - (nullable id)fw_propertyForName:(nonnull NSString *)name;

    Parameters

    name

    属性名称

    Return Value

    属性值

  • 设置强关联属性,支持KVO

    Declaration

    Objective-C

    - (void)fw_setProperty:(nullable id)object forName:(nonnull NSString *)name;

    Parameters

    object

    属性值

    name

    属性名称

  • 设置赋值关联属性,支持KVO,注意可能会产生野指针

    Declaration

    Objective-C

    - (void)fw_setPropertyAssign:(nullable id)object
                         forName:(nonnull NSString *)name;

    Parameters

    object

    属性值

    name

    属性名称

  • 设置拷贝关联属性,支持KVO

    Declaration

    Objective-C

    - (void)fw_setPropertyCopy:(nullable id)object forName:(nonnull NSString *)name;

    Parameters

    object

    属性值

    name

    属性名称

  • 设置弱引用关联属性,支持KVO,OC不支持weak关联属性

    Declaration

    Objective-C

    - (void)fw_setPropertyWeak:(nullable id)object forName:(nonnull NSString *)name;

    Parameters

    object

    属性值

    name

    属性名称

Bind

  • 给对象绑定上另一个对象以供后续取出使用,如果 object 传入 nil 则会清除该 key 之前绑定的对象

    Declaration

    Objective-C

    - (void)fw_bindObject:(nullable id)object forKey:(nonnull NSString *)key;

    Parameters

    object

    对象,会被 strong 强引用

    key

    键名

  • 给对象绑定上另一个弱引用对象以供后续取出使用,如果 object 传入 nil 则会清除该 key 之前绑定的对象

    Declaration

    Objective-C

    - (void)fw_bindObjectWeak:(nullable id)object forKey:(nonnull NSString *)key;

    Parameters

    object

    对象,不会被 strong 强引用

    key

    键名

  • 取出之前使用 bind 方法绑定的对象

    Declaration

    Objective-C

    - (nullable id)fw_boundObjectForKey:(nonnull NSString *)key;

    Parameters

    key

    键名

  • 给对象绑定上一个 double 值以供后续取出使用

    Declaration

    Objective-C

    - (void)fw_bindDouble:(double)doubleValue forKey:(nonnull NSString *)key;

    Parameters

    doubleValue

    double值

    key

    键名

  • 取出之前用 bindDouble:forKey: 绑定的值

    Declaration

    Objective-C

    - (double)fw_boundDoubleForKey:(nonnull NSString *)key;

    Parameters

    key

    键名

  • 给对象绑定上一个 BOOL 值以供后续取出使用

    Declaration

    Objective-C

    - (void)fw_bindBool:(BOOL)boolValue forKey:(nonnull NSString *)key;

    Parameters

    boolValue

    布尔值

    key

    键名

  • 取出之前用 bindBool:forKey: 绑定的值

    Declaration

    Objective-C

    - (BOOL)fw_boundBoolForKey:(nonnull NSString *)key;

    Parameters

    key

    键名

  • 给对象绑定上一个 NSInteger 值以供后续取出使用

    Declaration

    Objective-C

    - (void)fw_bindInt:(NSInteger)integerValue forKey:(nonnull NSString *)key;

    Parameters

    integerValue

    整数值

    key

    键名

  • 取出之前用 bindInt:forKey: 绑定的值

    Declaration

    Objective-C

    - (NSInteger)fw_boundIntForKey:(nonnull NSString *)key;

    Parameters

    key

    键名

  • 移除之前使用 bind 方法绑定的对象

    Declaration

    Objective-C

    - (void)fw_removeBindingForKey:(nonnull NSString *)key;

    Parameters

    key

    键名

  • 移除之前使用 bind 方法绑定的所有对象

    Declaration

    Objective-C

    - (void)fw_removeAllBindings;
  • 返回当前有绑定对象存在的所有的 key 的数组,数组中元素的顺序是随机的,如果不存在任何 key,则返回一个空数组

    Declaration

    Objective-C

    - (nonnull NSArray<NSString *> *)fw_allBindingKeys;
  • 返回是否设置了某个 key

    Declaration

    Objective-C

    - (BOOL)fw_hasBindingKey:(nonnull NSString *)key;

    Parameters

    key

    键名

Exchange

  • 交换类实例方法。复杂情况可能会冲突

    Declaration

    Objective-C

    + (BOOL)fw_exchangeInstanceMethod:(nonnull SEL)originalSelector
                        swizzleMethod:(nonnull SEL)swizzleSelector;

    Parameters

    originalSelector

    原始方法

    swizzleSelector

    交换方法

    Return Value

    是否成功

  • 交换类静态方法。复杂情况可能会冲突

    Declaration

    Objective-C

    + (BOOL)fw_exchangeClassMethod:(nonnull SEL)originalSelector
                     swizzleMethod:(nonnull SEL)swizzleSelector;

    Parameters

    originalSelector

    原始方法

    swizzleSelector

    交换方法

    Return Value

    是否成功

  • 交换类实例方法为block实现。复杂情况可能会冲突

    Note

    swizzleBlock示例:^(__unsafe_unretained UIViewController selfObject, BOOL animated){ ((void()(id, SEL, BOOL))objc_msgSend)(selfObject, swizzleSelector, animated); }

    Declaration

    Objective-C

    + (BOOL)fw_exchangeInstanceMethod:(nonnull SEL)originalSelector
                        swizzleMethod:(nonnull SEL)swizzleSelector
                            withBlock:(nonnull id)swizzleBlock;

    Parameters

    originalSelector

    原始方法

    swizzleSelector

    交换方法

    swizzleBlock

    实现block

    Return Value

    是否成功

  • 交换类静态方法为block实现。复杂情况可能会冲突

    Note

    swizzleBlock示例:^(__unsafe_unretained Class selfClass, BOOL animated){ ((void(*)(id, SEL, BOOL))objc_msgSend)(selfClass, swizzleSelector, animated); }

    Declaration

    Objective-C

    + (BOOL)fw_exchangeClassMethod:(nonnull SEL)originalSelector
                     swizzleMethod:(nonnull SEL)swizzleSelector
                         withBlock:(nonnull id)swizzleBlock;

    Parameters

    originalSelector

    原始方法

    swizzleSelector

    交换方法

    swizzleBlock

    实现block

    Return Value

    是否成功

  • 生成原始方法对应的随机交换方法

    Declaration

    Objective-C

    + (nonnull SEL)fw_exchangeSwizzleSelector:(nonnull SEL)selector;

    Parameters

    selector

    原始方法

    Return Value

    交换方法

Swizzle

  • 通用swizzle替换方法为block实现,支持类和对象,identifier有值且相同时仅执行一次。复杂情况不会冲突,推荐使用

    Declaration

    Objective-C

    + (BOOL)fw_swizzleMethod:(nullable id)target
                    selector:(nonnull SEL)originalSelector
                  identifier:(nullable NSString *)identifier
                   withBlock:(nonnull id _Nonnull (^)(
                                 __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                 IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    target

    目标类或对象

    originalSelector

    原始方法

    identifier

    唯一标识,有值且相同时仅执行一次

    block

    实现句柄

    Return Value

    是否成功

  • 使用swizzle替换类实例方法为block实现。复杂情况不会冲突,推荐使用

    Note

    Swift实现代码示例: NSObject.fw.swizzleInstanceMethod(UIViewController.self, selector: NSSelectorFromString(“viewDidLoad”)) { targetClass, originalCMD, originalIMP in let swizzleIMP: @convention(block)(UIViewController) -> Void = { selfObject in typealias originalMSGType = @convention©(UIViewController, Selector) -> Void let originalMSG: originalMSGType = unsafeBitCast(originalIMP(), to: originalMSGType.self) originalMSG(selfObject, originalCMD)

        // ...
    }
    return unsafeBitCast(swizzleIMP, to: AnyObject.self)
    

    }

    Declaration

    Objective-C

    + (BOOL)fw_swizzleInstanceMethod:(nonnull Class)originalClass
                            selector:(nonnull SEL)originalSelector
                           withBlock:
                               (nonnull id _Nonnull (^)(
                                   __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                   IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    originalClass

    原始类

    originalSelector

    原始方法

    block

    实现句柄

    Return Value

    是否成功

  • 使用swizzle替换类静态方法为block实现。复杂情况不会冲突,推荐使用

    Declaration

    Objective-C

    + (BOOL)fw_swizzleClassMethod:(nonnull Class)originalClass
                         selector:(nonnull SEL)originalSelector
                        withBlock:
                            (nonnull id _Nonnull (^)(
                                __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    originalClass

    原始类

    originalSelector

    原始方法

    block

    实现句柄

    Return Value

    是否成功

  • 使用swizzle替换类实例方法为block实现,identifier相同时仅执行一次。复杂情况不会冲突,推荐使用

    Declaration

    Objective-C

    + (BOOL)fw_swizzleInstanceMethod:(nonnull Class)originalClass
                            selector:(nonnull SEL)originalSelector
                          identifier:(nonnull NSString *)identifier
                           withBlock:
                               (nonnull id _Nonnull (^)(
                                   __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                   IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    originalClass

    原始类

    originalSelector

    原始方法

    identifier

    唯一标识

    block

    实现句柄

    Return Value

    是否成功

  • 使用swizzle替换类静态方法为block实现,identifier相同时仅执行一次。复杂情况不会冲突,推荐使用

    Declaration

    Objective-C

    + (BOOL)fw_swizzleClassMethod:(nonnull Class)originalClass
                         selector:(nonnull SEL)originalSelector
                       identifier:(nonnull NSString *)identifier
                        withBlock:
                            (nonnull id _Nonnull (^)(
                                __unsafe_unretained Class _Nonnull, SEL _Nonnull,
                                IMP _Nonnull (^_Nonnull __strong)(void)))block;

    Parameters

    originalClass

    原始类

    originalSelector

    原始方法

    identifier

    唯一标识

    block

    实现句柄

    Return Value

    是否成功

Class

  • 获取类方法列表,自动缓存,支持meta类(objc_getMetaClass)

    Declaration

    Objective-C

    + (nonnull NSArray<NSString *> *)fw_classMethods:(nonnull Class)clazz
                                          superclass:(BOOL)superclass;

    Parameters

    clazz

    指定类

    superclass

    是否包含父类,包含则递归到NSObject

    Return Value

    方法列表

  • 获取类属性列表,自动缓存,支持meta类(objc_getMetaClass)

    Declaration

    Objective-C

    + (nonnull NSArray<NSString *> *)fw_classProperties:(nonnull Class)clazz
                                             superclass:(BOOL)superclass;

    Parameters

    clazz

    指定类

    superclass

    是否包含父类,包含则递归到NSObject

    Return Value

    属性列表

  • 获取类Ivar列表,自动缓存,支持meta类(objc_getMetaClass)

    Declaration

    Objective-C

    + (nonnull NSArray<NSString *> *)fw_classIvars:(nonnull Class)clazz
                                        superclass:(BOOL)superclass;

    Parameters

    clazz

    指定类

    superclass

    是否包含父类,包含则递归到NSObject

    Return Value

    Ivar列表