2014-10-20 11 views
5

Napotkano na dziwne zachowanie podczas używania funkcji [NSMethodSignature getArgumentTypeAtIndex]. Zwraca mi znak "@" typu BOOL, który w złym zgodnie z celem-c type encodings. Jeśli korzystam z biblioteki objc \ runtime.h metoda method_getTypeEncoding Typ BOOL jest poprawnie reprezentowany jako "B", jednak nie rozumiem, dlaczego nie działa z warstwą wyższego poziomu NSMethodSignature. Poniższy kod demonstruje problem:Kodowanie BOOL jest nieprawidłowe od NSMethodSignature

-(void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    NSInvocation* inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(viewDidAppear:)]]; 
    const char* encFromGetArgument = [[inv methodSignature] getArgumentTypeAtIndex:2]; 

    const char* encFromMethodSignature = method_getTypeEncoding(class_getInstanceMethod([self class], @selector(viewDidAppear:)));; 
    const char* methodEncodingPure = [[[[NSString stringWithUTF8String:encFromMethodSignature] componentsSeparatedByCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]] componentsJoinedByString:@""] UTF8String];//remove stack sizes 


    NSLog(@"BOOL arg from NSMethodSignature: %s", encFromGetArgument); 
    NSLog(@"BOOL arg from objc/runtime.h: %c", methodEncodingPure[3]);//first type is for return, second is target, third is selector 
} 

Powyższy niespodziewanie (przynajmniej dla mężczyzn) drukuje następujące:

BOOL arg z NSMethodSignature: @

BOOL arg z objc/runtime.h : B

Używam obecnie własnej implementacji, aby uniknąć tego dziwnego zachowania, ale chcę wiedzieć, czy czegoś brakuje lub jest j. ust błąd. Moją jedyną wskazówką jest to, że BOOL jest prymitywny i tak nie może być użyty bezpośrednio podczas wywoływania metod obiektywnych-c. Jednak gdy spróbuję to sprawdzić [obiekt isKingOfClass: [NSNumber class]] zwraca NO.

UPDATE

Ok Mam XCode aktualizacji do najnowszej wersji (6.1) i 6A1052d sytuacji znacznie się poprawia. Jednak moim problemem jest teraz odróżnienie kodowania znaków bez znaku od prawdziwego kodowania Bool. Wiem, że w starych wersjach BOOL jest typedef jako char, ale w jaki sposób mogę dokonać prawdziwego kodowania BOOL? Teraz moje wyniki są następujące:

Dla Simulator iPhone6 ​​ a rzeczywistym urządzeniu iPhone6 ​​ dostałam:

argument 2: -------- -------- -------- -------- 
     type encoding (B) 'B' 
     flags {} 

BOOL arg from NSMethodSignature: B 
BOOL arg from objc/runtime.h: B 

co jest niesamowite, jednak dla symulator iphone4s, a prawdziwe urządzenie iPhone5 jestem otrzymywanie:

argument 2: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 

BOOL arg from NSMethodSignature: c 
BOOL arg from objc/runtime.h: c 

Jestem prawie pewien, że jeśli sprawdzę iPhone5s to Otrzymam takie samo wyjście jak iPhone6 ​​(ponieważ myślę, że to wszystko dotyczy architektury 64-bitowej). Więc moim pytaniem jest teraz, jak właściwie obejść starsze urządzenia, jak odróżnić dla nich BOOL z BOOL? Czy powinienem po prostu założyć, że jeśli kodowanie to "c", a argument jest równy "1", mamy TAK, a dla "0" mamy NIE?

+0

nie mogę odpowiedzieć, że pytanie, jednak nie jestem pewien, co ARC zrobi z obiektu zwróconego przez '[inw methodSignature]', z którego można dostać od ' const char * 'from. Oczywiście, że bufor znajduje się w domenie obiektów (pod jego zarządzaniem), więc wyobrażam sobie, że nie powinieneś tworzyć tymczasowego obiektu i usuwać go w ten sposób. – Droppy

+0

Ponieważ methodSignature to klasa ObjectiveC, jestem pewien, że będzie działał poprawnie w ARC. Główną kwestią jest to, dlaczego zwraca nieprawidłowe wartości. –

+0

Możliwe, że przyczyną problemu jest użycie tymczasowego obiektu. Wypróbuj za pomocą zmiennych, które nie są tymczasowe. – Droppy

Odpowiedz

5
char *buf1 = @encode(BOOL); 
NSLog(@"bool type is: %s", buf1); 

Na symulatorze 32bit, kodowanie (BOOL) zwraca 'c', a na 64 bit, zwraca 'B'. W Ustawieniach kompilacji zmień Architektury na $(ARCHS_STANDARD_32_BIT), a następnie zwróci Ci "C".

w pliku objc/objc.h.

#define OBJC_BOOL_DEFINED 

/// Type to represent a boolean value. 
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__ 
typedef bool BOOL; 
#else 
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used. 
#endif 

BOOL w wersji 32-bitowej jest typem znaku char. Możesz go odróżnić od znaku bez znaku.

@encode(char) --> 'c' 
@encode(unsigned char) --> 'C' 

Można powiedzieć, urządzenie jest w 32-bitowej lub 64-bitowej z here, a jeśli jest to w 32 bit, „c” jest ważna dla sprawdzenia BOOL.

+0

Doskonały punkt! odpowiedź Znalazłem moje rozwiązanie Zobacz moją aktualizację w pierwszym poście –

+0

Widziałem to, cieszę się, że pomogło – gabbler

+0

Świetne wyjaśnienie, dzięki! – PiotrCh

2

mam następujący na PO [inv methodSignature] w debugera:

(lldb) PO [inv methodSignature]

<NSMethodSignature: 0x7be7f660> 
    number of arguments = 3 
    frame size = 12 
    is special struct return? NO 
    return value: -------- -------- -------- -------- 
     type encoding (v) 'v' 
     flags {} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0} 
     memory {offset = 0, size = 0} 
    argument 0: -------- -------- -------- -------- 
     type encoding (@) '@' 
     flags {isObject} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 
    argument 1: -------- -------- -------- -------- 
     type encoding (:) ':' 
     flags {} 
     modifiers {} 
     frame {offset = 4, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 
    argument 2: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 
     modifiers {} 
     frame {offset = 8, offset adjust = 0, size = 4, size adjust = -3} 
     memory {offset = 0, size = 1} 

ma na mam drukowany na NSLog

BOOL arg from NSMethodSignature: c

Nie mogłem napisać komentarza, więc napisałem tę odpowiedź. Czy mógłbyś po twojej [inv methodSignature]?!I można zadowolić wyjściowego swój NSLog bezpośrednio po niej jest przypisany do encFromGetArgument

2

Na podstawie odpowiedzi @gabbler udało mi się sprawdzić, czy argument to bool, czy nie. Poniższy kod działa zarówno dla architektury 32 i 64-bitowym:

-(void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    NSInvocation* inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(viewDidAppear:)]]; 
    const char* encFromGetArgument = [[inv methodSignature] getArgumentTypeAtIndex:2]; 

    if(0 == strcmp(@encode(BOOL), encFromGetArgument)) 
    { 
     //BOOL val 
     NSLog(@"arg is bool"); 
    } 
    else 
    { 
     //not BOOL 
     NSLog(@"arg is not bool"); 
    } 
} 
Powiązane problemy