2013-04-20 4 views
1

Я столкнулся с каким-то странным поведением при попытке метода Swizzle isEqualToString: класса NSString. Вот код, о котором идет речь:Метод Swizzling isEqualToString

#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 называется (NSStringExtensionMethods), поэтому я включил rangeOfString Swizzle, чтобы показать, что я правильно swizzling методы и специально NSString объект успешно так Я мог бы устранить вопросы о проблемах class cluster.

Когда я создаю сборку для кода выше, вместо того, чтобы видеть нормальный 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:.

+1

Дон» t ** когда-либо ** swizzle вещи, которые реализуют шаблон FlyWeight и/или кластер Класса. Это просто пустая трата времени. – CodaFi

+2

Тратить время не всегда пустая трата времени. На данный момент мне в основном просто любопытно –

ответ

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") 
+0

Вау, я мог бы поклясться, что попробовал! Я действительно знаю кластеры классов и с успехом применяю методы, но почему-то я, должно быть, не обратил на это внимания. Спасибо, что вернули меня в правильном направлении! –

Смежные вопросы