Tôi đang cố gắng chuyển đối số chặn đến NSInvocation
nhưng ứng dụng bị treo. Lệnh gọi thực hiện một yêu cầu mạng và gọi các khối thành công hoặc thất bại. Tôi nghĩ rằng vấn đề là các khối được dealloced trước khi yêu cầu mạng kết thúc. Tôi quản lý để làm cho nó hoạt động với một số hack Block_copy
và nó không báo cáo bất kỳ rò rỉ nào bằng cách sử dụng Instruments.NSInvocation với đối số khối
Câu hỏi: - Có thể rò rỉ ở đó mặc dù Máy phân tích hoặc dụng cụ tĩnh không báo cáo nó? - Có cách nào tốt hơn để "giữ lại" khối không?
// Create the NSInvocation
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature];
[invoc setTarget:target];
[invoc setSelector:selector];
// Create success and error blocks.
void (^successBlock)(id successResponse) = ^(id successResponse) {
// Some success code here ...
};
void (^errorBlock)(NSError *error) = ^(NSError *error) {
// Some failure code here ...
};
/*
Without the two Block_copy lines, the block gets dealloced too soon
and the app crashes with EXC_BAD_ACCESS
I tried [successBlock copy] and [failureBlock copy] instead,
but the app still crashes.
It seems like Block_copy is the only way to move the block to the heap in this case.
*/
Block_copy((__bridge void *)successBlock);
Block_copy((__bridge void *)errorBlock);
// Set the success and failure blocks.
[invoc setArgument:&successBlock atIndex:2];
[invoc setArgument:&errorBlock atIndex:3];
[invoc retainArguments]; // does not retain blocks
// Invoke the method.
[invoc invoke];
Cập nhật: Tôi đã cập nhật mã thành bên dưới. Các khối là NSMallocBlocks
, nhưng ứng dụng vẫn bị treo.
// Create success and error blocks.
int i = 0;
void (^successBlock)(id successResponse) = ^(id successResponse) {
NSLog(@"i = %i", i);
// Some success code here ...
};
void (^errorBlock)(NSError *error) = ^(NSError *error) {
NSLog(@"i = %i", i);
// Some failure code here ...
};
/*** Both blocks are NSMallocBlocks here ***/
// Set the success and failure blocks.
void (^successBlockCopy)(id successResponse) = [successBlock copy];
void (^errorBlockCopy)(NSError *error) = [errorBlock copy];
/*** Both blocks are still NSMallocBlocks here - I think copy is a NoOp ***/
// Set the success and failure blocks.
[invoc setArgument:&successBlockCopy atIndex:2];
[invoc setArgument:&errorBlockCopy atIndex:3];
[invoc retainArguments]; // does not retain blocks
// Invoke the method.
[invoc invoke];
Các khối được truyền xuống trong chuỗi như sau:
NSInvocation
→ NSProxy
(NSInvocation
sử dụng forwardInvocation:
) → method1
→ methodN
methodN
cuối cùng gọi là thành công hay thất bại khối tùy thuộc vào HTTP phản ứng.
Tôi có cần sao chép khối ở mọi giai đoạn không? Ví dụ trên đã nói về NSInvocation
đầu tiên. Tôi có cần [invocation retainArguments];
ở mọi bước thích hợp không? Tôi đang sử dụng ARC.
Tôi đã thử successBlock = [successBlock cop y]; và errorBlock = [errorBlock copy]; nhưng tôi nhận được cùng một vụ tai nạn với lỗi này: địa chỉ không chứa một phần trỏ đến một phần trong một tập tin đối tượng . Như tôi đã đề cập, việc thêm các dòng Block_copy như đã đề cập ngăn ngừa sự cố, nhưng tôi không chắc liệu chúng có bị rò rỉ bộ nhớ hay không. – pshah
'Block_copy' mà bạn hiện đang sử dụng không có hiệu lực tài liệu. Tất cả những gì bạn thấy là các kết quả không xác định được gây ra bởi 'invoke' có vấn đề có hiệu ứng không xác định khác nhau. Nó không phải là một giải pháp thực sự. Và ngay cả những thây ma cũng sẽ không giúp bạn gỡ lỗi ở đây, vì chúng không thể giữ cho các đối tượng ngăn xếp còn sống giả tạo - một khi ngăn xếp phát triển trở lại, nó sẽ ghi đè lên chúng. – Tommy
Tôi đã được ấn tượng rằng gọi Block_copy buộc khối được lưu trên heap thay vì ngăn xếp. Và, tôi vẫn không thể tìm ra lý do tại sao truyền vào [successBlock copy] thay vì successBlock thành lời gọi sẽ không hoạt động. – pshah