2012-05-28 17 views
13

Also, ich habe Herumspielen mit dem objc-Laufzeit wieder (was für eine Überraschung), und ich fand einen interessanten Codeblock here:Warum können wir C-Strings nicht als SELs verwenden?

const char *sel_getName(SEL sel) { 
#if SUPPORT_IGNORED_SELECTOR_CONSTANT 
    if ((uintptr_t)sel == kIgnore) return "<ignored selector>"; 
#endif 
    return sel ? (const char *)sel : "<null selector>"; 
} 

Also, was das mir sagt, dass ein SEL entspricht zu einer C-Saite, in jedem Manierismus. Macht einen Hexadezimalspeicherauszüge der ersten 16 Bytes des SEL, die @selector(addObject:) enthält ergibt folgendes:

61 64 64 4F 62 6A 65 63 74 3A 00 00 00 00 00 00

die zu gleich die C-Saite .

Mit diesem gesagt, warum stürzt dieser Code, wenn ich die C-Zeichenfolge als Selektor verwenden?

SEL normalSEL = @selector(addObject:); 
SEL cStringSEL = (SEL) "addObject:"; 

NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1", @"2", nil]; 

[arr performSelector:normalSEL withObject:@"3"]; 
[arr performSelector:cStringSEL withObject:@"4"]; 

NSLog(@"%@", arr); 

Soweit ich das beurteilen kann, sind die Inhalte der Wähler die gleiche, also warum der Absturz auf dem zweiten mit der folgenden Fehlermeldung?

*** App beenden aufgrund nicht abgefangene Ausnahme 'NSInvalidArgumentException', Grund: '- [__ NSArrayM addObject:]: Unbekannter Selektor an Instanz gesendet 0x101918720' ***

+3

Beachten Sie, dass Sie 'sel_registerName()' verwenden können, um eine C-Zeichenfolge in eine gesegnete SEL umzuwandeln (im Grunde nimmt sie die Zeichenfolge hinter den Szenen auf, um die nachfolgende Zeigeridentität beizubehalten). Beachten Sie auch, dass Sie sich niemals direkt darauf verlassen sollten, dass ein SEL ein 'char *' ist. Es wird wahrscheinlich immer sein, aber das macht die Annahme nicht korrekt. – bbum

Antwort

22

Selektoren C-Strings interniert und sind verglichen mit ihrer Adresse, nicht ihre Inhalte. Der String-Inhalt wird nur für die Konvertierung in/aus einer externen Zeichenfolgendarstellung verwendet. Das Internieren wird durchgeführt, um die Leistung zu verbessern. Wenn die Laufzeitumgebung nach der Methodenimplementierung sucht, die mit einem Selektor übereinstimmt, kann sie die Selektorzeiger direkt vergleichen, anstatt jeden Zeiger zu dereferenzieren und die Zeichen zu vergleichen.

+0

Hmm ... nachdem ich in '__sel_registerName' geschaut habe, glaube ich, dass Sie Recht haben. Dennoch frage ich mich, wie groß der Leistungsunterschied tatsächlich wäre ... –

+0

Dies wird auch stark durch die string/selector-API impliziert; Siehe die Dokumentation für ['NSSelectorFromString()'] (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/doc/ uid/20000055-BCIEICGB) und seine Verbindung zu 'sel_registerName()'. –

+13

objc_msgSend läuft in diesen Tagen in etwa 8 Zyklen. Nicht viel Platz für einen strcmp() da drin;) –

Verwandte Themen