12

Tôi đang làm việc trên mã này, hoạt động không đồng bộ dài trên mạng và khi kết thúc nó kích hoạt khối hoàn thành một số thử nghiệm được thực hiện và nếu một biến được một giá trị nhất định khác hoạt động dài nên bắt đầu ngay lập tức:Cách khắc phục "chặn" khối mạnh trong khối này có thể dẫn đến chu trình giữ lại "

-(void) performOperation 
{ 

    void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request){ 


     int variable=0; 

     // Do completion operation A 
     //... 
     //... 

     // Do completion operation B     
     //Get the variable value 

     if(variable>0){ 
      [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock]; 
     } 

    }; 

//Perform the lenhgty operation with the above completionBlock 
    [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock]; 

} 

-(void) doLengthyAsynchronousOperationWithCompletionBlock: completionBlock 
{ 
    //Do some lengthy asynchronous stuff 
} 

với mã này tôi nhận được cảnh báo này từ trình biên dịch:

WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block 

tôi đã thay đổi:

void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request) 

trong:

__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request) 

nhưng tôi nhận được cảnh báo này khác:

WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle 

Làm thế nào tôi có thể sửa lỗi này?

Cảm ơn

Nicola

+0

Hãy xem [answer] này (http://stackoverflow.com/questions/7761074/arc-blocks-and-retain-cycles) –

Trả lời

29

CẢNH BÁO: Khối con trỏ biến 'completionBlock' chưa được định hình khi bị bắt bởi khối

Điều này xảy ra bởi vì các biến khối khởi tạo một khối đệ quy cần __block lưu trữ.

  • Các biến trong một khối được sao chép trừ khi được khai báo với __block, trong trường hợp này chúng được chuyển làm tham chiếu.
  • Khi một khối đệ quy được gán cho một biến khối, quá trình tạo diễn ra trước khi gán, và việc tạo ra như vậy sẽ kích hoạt một bản sao biến. Cho rằng biến chưa được gán, biến được sao chép sẽ là một giá trị xấu, và nó sẽ tạo ra một sự cố khi khối được chạy.
  • Nhưng nếu chúng tôi thêm __block, khối sẽ được tạo với tham chiếu đến biến thay thế. Sau đó, biến sẽ được khởi tạo cho khối đã tạo và khối sẽ sẵn sàng để sử dụng.

CẢNH BÁO: Capture 'completionBlock' mạnh mẽ trong khối này có khả năng dẫn đến một chu kỳ giữ

Điều này xảy ra bởi vì một biến khối là một tài liệu tham khảo mạnh để khối, và khối chính nó là tham chiếu biến (vì như chúng ta đã thấy trước đây, biến có một __block do đó nó được tham chiếu thay vì sao chép).

Vì vậy, chúng ta cần

  • Tham chiếu yếu vào biến mạnh mẽ bên trong khối.
  • Và tham chiếu mạnh mẽ bên ngoài để ngăn chặn chặn không được phân phối trong phạm vi của phương thức được tạo.
 
    void(^ completionBlock) (id obj, NSError *err, NSURLRequest *request); 
    void(^ __block __weak weakCompletionBlock) (id obj, NSError *err, NSURLRequest *request); 
    weakCompletionBlock = completionBlock = ^(id obj,NSError *err, NSURLRequest *request){ 
     [self lengthyAsyncMethod:weakCompletionBlock]; 
    }; 

Tên doLengthyAsynchronousOperationWithCompletionBlock gợi ý rằng phương pháp này có thể sống lâu hơn phạm vi phương pháp hợp khối được tạo ra. Cho rằng trình biên dịch không sao chép một khối thông qua như một đối số, đó là trách nhiệm của phương pháp này để sao chép khối này. Nếu chúng ta đang sử dụng khối này với mã nhận biết khối (ví dụ: dispatch_async()), điều này xảy ra tự động. Nếu chúng ta đã gán khối này cho một biến mẫu, chúng ta sẽ cần một @property(copy) và một tham chiếu yếu đến bản thân bên trong khối, nhưng đây không phải là trường hợp, vì vậy chúng ta chỉ sử dụng self.

+0

Tôi đã thử một cái gì đó như thế này và nó có vẻ làm việc: Tôi lưu khối trong một thuộc tính copy của controller thì tôi chuyển thuộc tính là completionBlock. Nicola –

+0

bạn không cần '__block' trên' completionBlock' vì nó không bao giờ được sử dụng trong một khối! trên thực tế, nó không bao giờ được sử dụng ở bất cứ nơi nào – newacct

+1

cũng có, 'tự' không phải là những gì cảnh báo của OP là về. Chúng ta không biết liệu 'self' có tham chiếu mạnh mẽ đến khối (OP không cho chúng ta thấy đủ mã để xem điều đó), vì vậy không an toàn để cho rằng nó cần phải là' __weak' – newacct

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