5

Dla mnie zdolność Objective-C do reagowania, opisu i bałaganu w otoczeniu jest tam, gdzie jest. Zaczyna się to, na poziomie podstawowym, z niezmienną zdolnością do odwoływania się do _cmd, w dowolnym momencie i uzyskiwania aktualnego SEL. Stamtąd, to zależy od ciebie co NSInvocation inkantacje lub wykonawcze szykany wybrać do udziału w.Introspekcja bieżącego kontekstu bloku à la _cmd wewnątrz metody

Teraz wewnątrz bloku, nadal można nazwać _cmd i dostać mgliste opis obecnego „kontekstu”, czyli

__30-[RoomController awakeFromNib]_block_invoke123RoomController 

Opisowy? Tak. Informacyjny? Okay ... Ale nie tak przydatne. Jak uzyskać dynamiczne i dokładne informacje o środowisku wykonawczym wewnątrz bloku, w szczególności podpis wywołujący, argumenty itp.?

I have found a useful little method to "describe" a block z wyprzedzeniem, które daje dobry przykład rodzaju informacji, które mam zamiar zgromadzić W PRZESZŁOŚCI.

typedef void(^blockHead)(NSString*); 
blockHead v = ^(NSString*sandy) { NSLog(@"damnDog",nil); }; 
Log([v blockDescription]); 

[v blockDescription] = <NSMethodSignature: 0x7fd6fabc44d0> 
    number of arguments = 2 
    frame size = 224 
    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, isBlock} 
    modifiers {} 
    frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0} 
    memory {offset = 0, size = 8} 
argument 1: -------- -------- -------- -------- 
    type encoding (@) '@"NSString"' 
    flags {isObject} 
    modifiers {} 
    frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0} 
    memory {offset = 0, size = 8} 
     class 'NSString' 
+1

nie można tak naprawdę wiedzieć nic o bloku wewnątrz bloku, chyba że można się do niego jakoś odwołać. BTW, dlaczego chcesz poznać te informacje? –

+0

Ponieważ bloki API rozmnażają się ... często trudno jest powiedzieć dzwoniącemu bloku itp. Kompilator dopuszcza niedopasowane podpisy ...niepoprawna liczba argumentów i wiele metod o tej samej nazwie, ale różne rodzaje bloków itp. = współistnienie bez zarzutu ... Byłoby miło wiedzieć, czasami, co tak naprawdę się dzieje ... nie tylko co "Myślę, że" się dzieje. –

+1

możesz sprawdzić typ bloku przed wywołaniem go, ale nie możesz wiele zrobić wewnątrz bloku, ponieważ jest on już wywoływany prawdopodobnie z niepoprawnymi parametrami. –

Odpowiedz

5

Jeśli kopiesz wystarczająco głęboko, jest to możliwe z niektórymi zespołami docelowymi.

Istnieją trzy główne architektury zostanie uruchomiony kod objective-c dalej, które są:

  • x86: iOS Simulator i starożytne Mac
  • x86_64: Mac OSX
  • ARM: iOS Devices .

Korzystanie debuggera lldb, wraz z wieloma hacking, mam wymyślić rejestrów, które są używane dla każdej platformy (do trzymania wskaźnik Blok):

  • x86: ecx/edi
  • x86_64: rcx/rdi
  • ARM: r0/r4

Na wszystkich platformach wartości wydają się być w dwóch oddzielnych rejestrach, być może jeden od punktu wywołującego i jeden od przekazanego argumentu.

Korzystając z tych informacji, zrobiłem kilka makr, które będą działać zarówno z GCC i Clang aby uzyskać wartości tych rejestrów w C zmiennej:

#if TARGET_CPU_X86_64 
// OSX, the block pointer is in the register 'rcx'. 
// The 'mov' instruction does not clobber the register, 
// So we can simply (ab)use that here. 
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("mov %%rcx, %0" : "=r"(__block_self_tmp)); __block_self_tmp; }) 
#elif TARGET_CPU_X86 
// iOS Simulator, the block pointer is in the register 'ecx'. 
// Same deal as with x86_64 code, except it's in a 32-bit register. 
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("mov %%ecx, %0" : "=r"(__block_self_tmp)); __block_self_tmp; }) 
#elif TARGET_CPU_ARM64 
// iOS Device, ARM64 (iPhone 5S, iPad Mini 2, iPad Air). 
// The block pointer is in the x0 register, and the x4 register. 
// Similar code to the TARGET_CPU_ARM function. 
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("str x0, [%0]" :: "r"(&__block_self_tmp)); __block_self_tmp; }) 
#elif TARGET_CPU_ARM 
// iOS Device, the block pointer is in register 'r0'. 
// The 'mov' (move) instruction clobbers the r0 register 
// (which messes up the debugger) for whatever reason, 
// so we use the 'str' (store) instruction instead. 
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("str r0, [%0]" :: "r"(&__block_self_tmp)); __block_self_tmp; }) 
#endif 

void blockTest() { 
    __block void *blockPtr = NULL; 
    void (^myBlock)() = ^{ 
     id this = BLOCK_GET_SELF(); 

     printf("this is:\t\t0x%.8lx\n", (uintptr_t) this); 
     printf("blockPtr is:\t0x%.8lx\n", (uintptr_t) blockPtr); 
    }; 

    // example using dispatch 
    blockPtr = (__bridge void *) myBlock; 
    dispatch_async(dispatch_get_main_queue(), myBlock); 
} 

Output, iPhone 5 z systemem iOS 7 Beta 2 :

 
this is:  0x17e7c890 
blockPtr is: 0x17e7c890 

Proszę dać mi znać o wszelkich problemach z tym kodem i mam nadzieję, że ci to pomoże!

Powiązane problemy