5

Đối với tôi, khả năng phản ứng, mô tả và gây rối của môi trường xung quanh là nơi nó ở. Điều này bắt đầu, ở cấp độ cơ bản, với khả năng vững chắc để tham chiếu đến _cmd, tại bất kỳ thời điểm nào và nhận số SEL hiện tại. Từ đó, nó là tùy thuộc vào bạn những gì NSInvocation câu thần chú hay xảo ngôn runtime bạn chọn để tham gia vào.Nhìn vào bối cảnh khối hiện tại, à la _cmd bên trong một phương pháp

Bây giờ, bên trong một khối, bạn vẫn có thể gọi _cmd và có được một mô tả mơ hồ của "bối cảnh" hiện nay, tức là

__30-[RoomController awakeFromNib]_block_invoke123RoomController 

Mô tả? Có. Thông tin? Được rồi ... Nhưng không hữu ích lắm. Làm thế nào để tôi nhận được thông tin thời gian chạy động và chính xác bên trong một khối, cụ thể là chữ ký gọi, args, v.v ...?

I have found a useful little method to "describe" a block trước thời hạn cung cấp một ví dụ tốt về loại thông tin mà tôi hy vọng sẽ thu hút INSIDE khối.

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

bạn thực sự không thể biết bất kỳ điều gì về chính khối đó trong khối trừ khi bạn có thể tham khảo nó bằng cách nào đó. BTW, tại sao bạn muốn biết những thông tin này? –

+0

Khi các khối API sinh sôi nảy nở .. thường khó để nói cho người gọi của khối, v.v. Trình biên dịch cho phép các chữ ký không khớp ...số lượng đối số không chính xác và nhiều phương thức, cùng tên, nhưng các loại khối khác nhau, v.v. = cùng tồn tại mà không có khiếu nại ... Sẽ rất thú vị khi biết, đôi khi, điều thực sự xảy ra ... không chỉ là những gì "Tôi nghĩ" đang xảy ra. –

+1

bạn có thể kiểm tra loại khối trước khi gọi nó, nhưng bạn không thể làm nhiều bên trong khối vì nó đã được gọi là có thể với tham số không chính xác –

Trả lời

5

Nếu bạn đào sâu đủ, thực sự có thể với một số lắp ráp nhắm mục tiêu cụ thể.

Có ba kiến ​​trúc chính bạn sẽ được chạy mã Objective-C trên, đó là:

  • x86: iOS Simulator, và Mac cổ
  • x86_64: Mac OSX
  • ARM: iOS Devices .

Sử dụng trình gỡ lỗi LLĐB, cùng với rất nhiều hack, tôi đã đưa ra các thanh ghi được sử dụng cho mỗi nền tảng (cho giữ con trỏ khối):

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

Trên tất cả các nền tảng, các giá trị xuất hiện trong hai thanh ghi riêng biệt, có thể là một từ điểm gọi và một từ đối số được chuyển.

Sử dụng thông tin này, tôi đã thực hiện một vài macro mà sẽ làm việc với cả hai GCC và Clang để có được các giá trị của thanh ghi cho biết vào một biến C:

#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 iOS chạy 7 Beta 2 :

 
this is:  0x17e7c890 
blockPtr is: 0x17e7c890 

Vui lòng cho tôi biết về bất kỳ sự cố nào với mã này và tôi hy vọng nó sẽ giúp bạn!

Các vấn đề liên quan