代码之家  ›  专栏  ›  技术社区  ›  Ortwin Gentz

如何在iOS上swizzle类方法?

  •  30
  • Ortwin Gentz  · 技术社区  · 14 年前

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

    我试过了,但没用:

    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);
    }
    
    1 回复  |  直到 11 年前
        1
  •  56
  •   Ortwin Gentz    14 年前

    原来,我就在不远处。这个实现对我很有用:

    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);
    }
    
        2
  •  0
  •   yoAlex5    4 年前

    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]

    推荐文章