2009-11-25 21 views
10

Ví dụ: Khi phương thức -fooBar của tôi được gọi, tôi muốn nó đăng nhập vào bảng điều khiển mà phương thức khác mà lớp kia gọi là phương thức đó.Làm thế nào để tìm ra ai đã gọi một phương pháp?

Ngay bây giờ, tôi chỉ biết làm thế nào để đăng nhập tên phương pháp foobar bản thân và lớp của nó, với điều này:

_cmd 

[self class] 

Đây có phải là có thể tìm ra?

Trả lời

36

Trong mã được tối ưu hóa hoàn toàn, không có cách chắc chắn 100% để xác định người gọi đến một phương thức nhất định. Trình biên dịch có thể sử dụng tối ưu hóa cuộc gọi đuôi trong khi trình biên dịch có hiệu quả tái sử dụng khung ngăn xếp của người gọi cho callee.

Để xem ví dụ về điều này, hãy đặt điểm ngắt trên bất kỳ phương thức đã cho nào bằng gdb và xem backtrace. Lưu ý rằng bạn không thấy objc_msgSend() trước mỗi cuộc gọi phương thức. Đó là bởi vì objc_msgSend() thực hiện một cuộc gọi đuôi đến việc thực hiện từng phương thức.

Trong khi bạn có thể biên dịch ứng dụng của bạn không được tối ưu hóa, bạn sẽ cần các phiên bản không được tối ưu hóa của tất cả các thư viện hệ thống để tránh chỉ một vấn đề này.

Và đây chỉ là một vấn đề; có hiệu lực, bạn đang hỏi "làm cách nào để phát minh lại CrashTracer hoặc gdb?". Một vấn đề rất khó khăn khi nghề nghiệp được thực hiện. Trừ khi bạn muốn "gỡ lỗi công cụ" để được sự nghiệp của bạn, tôi sẽ khuyên bạn nên chống lại đi xuống con đường này.

Bạn đang thực sự cố gắng trả lời câu hỏi nào?

+3

Đây là một câu trả lời. –

+7

@alexgray Làm cách nào để chống trả lời?Câu trả lời là chính xác trong phạm vi và quy mô của vấn đề và, với sự chấp nhận và câu hỏi cuối cùng, hy vọng dẫn đầu OP xuống một con đường để thành công. – bbum

3

Không thể trong trường hợp chung mà không thực sự đi bộ ngăn xếp. Thậm chí không có một đảm bảo rằng một đối tượng khác gửi tin nhắn gọi là phương thức. Ví dụ, nó có thể được gọi từ một khối trong một trình xử lý tín hiệu.

1

Thông tin này có thể lấy được bằng cách sử dụng DTrace.

1

Tạo macro thêm __FUNCTION__ vào tên hàm vào cuộc gọi hàm. Macro này sau đó sẽ gọi hàm của bạn với tham số bổ sung của char * vào hàm đích.

+0

đó giả định rằng bạn có thể kiểm soát người gọi và có thể thay đổi ABI giữa người gọi và cal lee bằng cách thay đổi các đối số, mà hiếm khi là trường hợp. – bbum

6

Làm thế nào về this:

NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; 

NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"]; 
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]]; 
[array removeObject:@""]; 

NSLog(@"Class caller = %@", [array objectAtIndex:3]); 
NSLog(@"Method caller = %@", [array objectAtIndex:4]); 

Tín dụng cho tác giả ban đầu, intropedro.

+3

Điều đó sẽ không hoạt động trong mã được tối ưu hóa hoàn toàn khi tối ưu hóa cuộc gọi đuôi làm cho khung biến mất hoàn toàn khỏi ngăn xếp. – bbum

2

tài phương pháp dưới đây
index đèo mà bạn muốn hiển thị phương pháp và thông qua -1 nếu bạn muốn hiển thị ngăn xếp đầy đủ các phương pháp

+(void) methodAtIndex:(int)index{ 
    void* callstack[128]; 
    int frames = backtrace(callstack, 128); 
    char** strs = backtrace_symbols(callstack, frames); 

    if (index == -1) { 
     for (int i = 0; i < frames; ++i) { 
      printf("%s\n", strs[i]); 
     } 
    } 
    else { 
     if (index < frames) { 
      printf("%s\n", strs[index]); 
     } 
    } 
    free(strs); 

} 
+0

Tôi nhận được 'lỗi: cảnh báo: không thể lấy con trỏ cmd (thay thế NULL): không có biến có tên '_cmd' được tìm thấy trong khung này' – ReDetection

0

Tôi đã cố gắng để bắt người, làm thế nào và khi nào kích thước thay đổi cửa sổ và đã làm một số thủ công:

- (void)logWindowWidth:(NSString *)whoCalls { 
    NSLog(@"%@", whoCalls); 
    NSLog(@"self.window.size.width %f", self.window.size.width); 
} 

-(void)someMethod { 
    [self logWindowWidth:@"someMethod - before"]; 
    ... 
    [self logWindowWidth:@"someMethod - after"]; 
} 

-(void)anotherMethod { 
    [self logWindowWidth:@"anotherMethod - before"]; 
    ... 
    [self logWindowWidth:@"anotherMethod - after"]; 
} 
1
NSLog(@"Show stack trace: %@", [NSThread callStackSymbols]); 
Các vấn đề liên quan