1

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:都在NSStringcalled类别中定义(NSStringExtensionMethods),因此我包含了rangeOfStringswizzle 以表明我正在正确地调配方法,特别是NSString成功地调配了一个对象,因此我可以消除有关类集群问题的问题。

当我为上面的代码生成程序集时,我没有看到正常的objc_msgSend调用,而是看到了类似l_objc_msgSend_fixup_isEqualToString_. 这让我找到了更多关于objective-c vtable的信息,似乎isEqualToString:可以在其中找到:

static const char * const defaultVtable[] = {
    "allocWithZone:", 
    "alloc", 
    "class", 
    "self", 
    "isKindOfClass:", 
    "respondsToSelector:", 
    "isFlipped", 
    "length", 
    "objectForKey:", 
    "count", 
    "objectAtIndex:", 
    "isEqualToString:", 
    "isEqual:", 
    "retain", 
    "release", 
    "autorelease", 
};

我整天都在挖掘objective-c 源代码和互联网,以了解如何以某种方式仍然能够 swizzle isEqualToString:

4

1 回答 1

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")
于 2013-04-20T17:58:33.893 回答