【问题标题】:How to swizzle a class method on iOS?如何在 iOS 上调整类方法?
【发布时间】:2011-03-17 02:24:48
【问题描述】:

方法调配对实例方法非常有效。现在,我需要调配一个类方法。知道怎么做吗?

试过了,还是不行:

void SwizzleClassMethod(Class c, SEL orig, SEL new) {

Method origMethod = class_getClassMethod(c, orig);
Method newMethod = class_getClassMethod(c, new);

if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
    class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
    method_exchangeImplementations(origMethod, newMethod);
}

【问题讨论】:

    标签: ios iphone objective-c swizzling


    【解决方案1】:

    Objective-C 使用类别混搭

    @interface cA : NSObject {
    
    }
    @end
    
    @implementation cA
    
    +(NSString*) cClassFooA {
        return @"class fooA";
    }
    
    -(NSString*) cFooA {
        return @"fooA";
    }
    
    @end
    
    
    @interface cB : NSObject {
    
    }
    @end
    
    @implementation cB
    
    +(NSString*) cClassFooB {
        return @"class fooB";
    }
    
    -(NSString*) cFooB {
        return @"fooB";
    }
    
    @end
    

    NSObject+Swizzling.h

    #import <Foundation/Foundation.h>
    
    @interface NSObject (Swizzling)
    
    + (void)cExchangeClassWithCls1:(Class)cls1 Sel1:(SEL)sel1 Cls2:(Class)cls2 Sel2:(SEL)sel2;
    + (void)cExchangeInstanceWithCls1:(Class)cls1 Sel1:(SEL)sel1 Cls2:(Class)cls2 Sel2:(SEL)sel2;
    
    @end
    

    NSObject+Swizzling.m

    #import "NSObject+Swizzling.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (Swizzling)
    
    + (void)cExchangeClassWithCls1:(Class)cls1 Sel1:(SEL)sel1 Cls2:(Class)cls2 Sel2:(SEL)sel2 {
    
        Method originalMethod = class_getClassMethod(cls1, sel1);
        Method swizzledMethod = class_getClassMethod(cls2, sel2);
    
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
    + (void)cExchangeInstanceWithCls1:(Class)cls1 Sel1:(SEL)sel1 Cls2:(Class)cls2 Sel2:(SEL)sel2 {
    
        Method originalMethod = class_getInstanceMethod(cls1, sel1);
        Method swizzledMethod = class_getInstanceMethod(cls2, sel2);
    
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    @end
    

    通过 Objective-C 使用

    - (void)testCExchangeClass {
        [NSObject cExchangeClassWithCls1:[cA class] Sel1:@selector(cClassFooA) Cls2:[cB class] Sel2:@selector(cClassFooB)];
    
        XCTAssertEqual(@"class fooB", [cA cClassFooA]);
    }
    
    - (void)testCExchangeInstance {
        [NSObject cExchangeInstanceWithCls1:[cA class] Sel1:@selector(cFooA) Cls2:[cB class] Sel2:@selector(cFooB)];
    
        XCTAssertEqual(@"fooB", [[[cA alloc] init] cFooA]);
    }
    

    [Add Swift as an consumer]

    通过 Swift 使用

    func testCExchangeClass() {
        NSObject.cExchangeClass(withCls1: sA.self, sel1: #selector(sA.sClassFooA), cls2: sB.self, sel2: #selector(sB.sClassFooB))
    
        XCTAssertEqual("class fooB", sA.sClassFooA())
    }
    
    func testCExchangeInstance() {
        NSObject.cExchangeInstance(withCls1: sA.self, sel1: #selector(sA.sFooA), cls2: sB.self, sel2: #selector(sB.sFooB))
    
        XCTAssertEqual("fooB", sA().sFooA())
    }
    

    [Swift swizzling]

    【讨论】:

      【解决方案2】:

      原来,我离得不远。这个实现对我有用:

      void SwizzleClassMethod(Class c, SEL orig, SEL new) {
      
          Method origMethod = class_getClassMethod(c, orig);
          Method newMethod = class_getClassMethod(c, new);
      
          c = object_getClass((id)c);
      
          if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
              class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
          else
              method_exchangeImplementations(origMethod, newMethod);
      }
      

      【讨论】:

      • 嗯...假设我们改为使用Class cc=object_getClass((id)c)。需要在cc中添加方法是可以理解的,但是为什么要从cc中取类方法呢?您不应该从 c 获取类方法吗?我很困惑......
      • Yuhi,你是对的,我已经更改了代码以对原始类进行方法解析,而不是元类。旧的解决方案也很有效,所以我并没有真正打扰。
      • 我的错。我将object_getClass 输入到objc_getClass 中。我会马上删除我的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多