2011-10-13 16 views
28

Làm việc trên một dự án iOS nhắm mục tiêu 4.0 và 5.0, sử dụng ARC.ARC, Chặn và giữ lại chu kỳ

Chạy vào một vấn đề liên quan đến các khối, ARC và tham chiếu một đối tượng từ bên ngoài khối. Dưới đây là một số mã:

__block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
    [operation setCompletionBlock:^ { 
     if ([operation isCancelled]) { 
      return; 
     } 

... do stuff ... 

operation = nil; 
}]; 

Trong trường hợp này, trình biên dịch đưa ra cảnh báo rằng việc sử dụng 'thao tác' trong khối sẽ dẫn đến chu kỳ lưu giữ. Dưới ARC, __block hiện giữ lại biến.

Nếu tôi thêm __unsafe_unretained, trình biên dịch sẽ giải phóng đối tượng ngay lập tức, vì vậy rõ ràng điều đó sẽ không hoạt động.

Tôi đang nhắm mục tiêu 4.0 nên tôi không thể sử dụng __weak.

tôi đã cố gắng làm một cái gì đó như thế này:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation; 

nhưng trong khi weakOperation không phải là con số không, không ai trong số đó là thuộc tính này được dân cư khi bên trong khối.

Cách tốt nhất để xử lý tình huống này do các ràng buộc của dự án được liệt kê ở trên là gì?

Trả lời

23

Giả sử đảm bảo tiến độ, chu kỳ lưu giữ có thể chính xác như bạn muốn. Bạn rõ ràng phá vỡ chu kỳ giữ lại ở cuối khối, do đó, nó không phải là một chu kỳ lưu giữ vĩnh viễn: khi khối được gọi, chu trình bị hỏng.

Nếu bạn có thứ gì đó khác để duy trì hoạt động, bạn có thể lưu trữ tham chiếu vào biến số __weak hoặc __unsafe_unretained và sau đó sử dụng biến đó từ trong khối của bạn. Không cần phải __block -qualify biến trừ khi bạn vì một lý do nào đó cần thay đổi ràng buộc của biến trong khối; vì bạn không có chu kỳ giữ lại để phá vỡ nữa, bạn không cần gán bất kỳ thứ gì cho biến yếu.

+1

Tôi đã có điều 'chu kỳ không lưu giữ' được khắc sâu trong đầu, tôi thậm chí còn không nghĩ về cách bạn mô tả. Duh. Câu hỏi tiếp theo - bất kỳ cách nào để làm im lặng cảnh báo trình biên dịch? Nó sẽ làm tôi phát điên. – Hunter

+1

Xem ["Kiểm soát chẩn đoán thông qua Pragmas"] (http://clang.llvm.org/docs/UsersManual.html#diagnostics_pragmas) trong hướng dẫn sử dụng của Clang. Bạn sẽ chỉ cần tìm ra cờ cảnh báo nào cần bỏ qua. –

+4

Đó là '#pragma clang diagnostic ignored" -Warc-retain-cycles "', bởi by by. –

1

này dường như là vấn đề được mô tả bởi Conrad Stoll trong Blocks, Operations, and Retain Cycles, nhưng writeup mình bỏ lỡ một vài điểm quan trọng:

  • __block trông giống như cách Apple khuyến cáo để tránh một tham chiếu mạnh để biến bị bắt trong MRC nhưng hoàn toàn không cần thiết trong chế độ ARC. Trong trường hợp này, nó hoàn toàn không cần thiết trong chế độ ARC; nó cũng không cần thiết trong chế độ MRC mặc dù cách giải quyết trọng lượng nhẹ hơn tiết lộ nhiều hơn: void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
  • Ở chế độ ARC, bạn cần cả tham chiếu mạnh mẽ (để bạn có thể thêm nó vào hàng đợi) và tham chiếu yếu/không an toàn

giải pháp đơn giản nhất như sau:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
AFHTTPRequestOperation * __unsafe_unretained unretainedOperation = operation; 

[operation setCompletionBlock:^ { 
    if ([unretainedOperation isCancelled]) { 
    return; 
    } 
    ... do stuff ... 
}]; 

Thậm chí nếu bạn phá vỡ chu kỳ tài liệu tham khảo, không có lý do cho the Block để giữ lại AFHTTPRequestOperation ở nơi đầu tiên (giả sử các hoạt động giữ bản thân còn sống cho đến khi t hoàn thành xử lý hoàn thành, mà không phải lúc nào cũng được bảo đảm nhưng nói chung là đúng và được giả định bởi ARC nếu nó được gọi bằng cách sử dụng thêm self ngăn xếp cuộc gọi).

Sửa lỗi tốt nhất dường như cập nhật thành latest AFNetworking, chuyển hoạt động đó vào khối làm đối số.

+0

__block không hoàn toàn không cần thiết. Theo mặc định, tất cả các biến, được giữ lại bởi khối sẽ là const bên trong nó, vì vậy bạn không thể thay đổi giá trị của chúng. Ở đây __block đến để giải cứu. –