1

クラスでMethod Swizzle を実行しようとすると、奇妙な動作が発生しisEqualToString:ます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:とは両方ともcalledrangeOfString:のカテゴリで定義されているため、メソッドを正しく、特にオブジェクトを正常にスウィズルしていることを示すためにスウィズルを含めて、クラス クラスターの問題に関する疑問を解消できるようにしました。NSString(NSStringExtensionMethods)rangeOfStringNSString

上記のコードのアセンブリを生成すると、通常の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", 
};

私はどうにかしてまだ swizzle できるようにする方法について、objective-c のソースとインターネットを一日中掘り下げてきました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 に答える