提问人:Ortwin Gentz 提问时间:7/17/2010 最后编辑:Ortwin Gentz 更新时间:4/24/2023 访问量:19170
如何在 iOS 上摆动类方法?
How to swizzle a class method on iOS?
问:
方法切换非常适合实例方法。现在,我需要 swizzle 一个类方法。知道怎么做吗?
试过这个,但它不起作用:
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);
}
答:
57赞
Ortwin Gentz
7/17/2010
#1
原来,我离得并不远。这个实现对我有用:
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);
}
评论
0赞
Yuji
7/17/2010
嗯。。。假设我们做了.需要将方法添加到 中是可以理解的,但是为什么要从 中获取类方法呢?你不应该从中获取类方法吗?我很困惑......Class cc=object_getClass((id)c)
cc
cc
c
0赞
Ortwin Gentz
7/20/2010
Yuhi,你是对的,我已经更改了代码以对原始类而不是元类进行方法解析。旧的解决方案也有效,所以我并没有真正打扰。
0赞
Di Wu
12/1/2014
我的错。我错误地将object_getClass输入到objc_getClass中。我一会儿会删除我的答案。
0赞
Gibezynu Nu
5/22/2023
由于某种原因,它不起作用。将class_getClassMethod与method_setImplementation一起使用,请参阅我尝试旋转 newrelic.com/blog/best-practices/right-way-to-swizzle +[NSArray array]
0赞
Ortwin Gentz
5/22/2023
@GibezynuNu 像 NSArray 这样的 Swizzling 类集群会导致问题。框架依赖于某种功能,而 NSArray 的旋转将打破这些假设,并导致极难重现的错误。即使你可以这样做,也请不要这样做。
2赞
yoAlex5
6/17/2020
#2
Objective-C 旋转
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]);
}
通过 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())
}
评论