方法Swizzling isEqualToString

时间:2013-04-20 03:47:28

标签: objective-c objective-c-runtime

我在isEqualToString:课程中尝试Method Swizzle NSString时遇到了一些奇怪的行为。以下是有问题的代码:

#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>

@interface NSString (SwizzleString)
- (BOOL) custom_isEqualToString:(NSString *)aString;
- (NSRange)custom_rangeOfString:(NSString *)aString;
@end

@implementation NSString (SwizzleString)

- (BOOL) custom_isEqualToString:(NSString *)aString;
{
    NSLog(@"Inside custom_isEqualToString method definition");
    return [self custom_isEqualToString:aString];
}

- (NSRange)custom_rangeOfString:(NSString *)aString;
{
    NSLog(@"Inside custom_rangeOfString method definition");
    return [self custom_rangeOfString:aString];
}

@end

int main(int argc, const char * argv[])
{

    Method m1, m2;

    m1 = class_getInstanceMethod([NSString class], @selector(isEqualToString:));
    m2 = class_getInstanceMethod([NSString class], @selector(custom_isEqualToString:));
    method_exchangeImplementations(m1, m2);

    m1 = class_getInstanceMethod([NSString class], @selector(rangeOfString:));
    m2 = class_getInstanceMethod([NSString class], @selector(custom_rangeOfString:));
    method_exchangeImplementations(m1, m2);

    NSString *foo = @"Foo";

    // Does not log anything, is still using isEqualToString: implementation
    [foo isEqualToString:@"Foo"];
    // Also does not log anything, since it is using the method implementation from isEqualToString:
    [foo custom_isEqualToString:@"Foo"];

    // Does log something because rangeOfString now uses custom_rangeOfString IMP
    [foo rangeOfString:@"Foo"];
    // Does not log anything because it uses the method implementation from rangeOfString:
    [foo custom_rangeOfString:@"Foo"];
}

isEqualToString:rangeOfString:都在名为NSString的{​​{1}}的类别中定义,因此我添加了(NSStringExtensionMethods)混合以显示我{&#39}。正确地混合方法,特别是成功rangeOfString个对象,这样我就可以消除有关class cluster个问题的问题。

当我为上面的代码生成程序集时,我没有看到正常的NSString调用,而是查看objc_msgSend之类的内容。这让我发现了objective-c vtable的更多信息,其中l_objc_msgSend_fixup_isEqualToString_似乎可以找到:

isEqualToString:

我整天都在挖掘目标c来源和互联网,以了解如何以某种方式仍然可以调动static const char * const defaultVtable[] = { "allocWithZone:", "alloc", "class", "self", "isKindOfClass:", "respondsToSelector:", "isFlipped", "length", "objectForKey:", "count", "objectAtIndex:", "isEqualToString:", "isEqual:", "retain", "release", "autorelease", };

1 个答案:

答案 0 :(得分:0)

如您所知,这是一个类集群。您需要实际类,而不是公共类,所以只需询问您拥有的字符串对象:

NSString *foo = @"Foo";

m1 = class_getInstanceMethod([foo class], @selector(isEqualToString:));
m2 = class_getInstanceMethod([foo class], @selector(custom_isEqualToString:));
method_exchangeImplementations(m1, m2);

使用类名本身也有一个脆弱的选择:

NSClassFromString(@"__NSCFConstantString")
NSClassFromString(@"__NSCFString")