2012-08-06 27 views
5

In this question, tôi được hỏi về đoạn mã sau và duy trì chu kỳ:tài liệu tham khảo yếu trong khối và duy trì chu kỳ

__weak Cell *weakSelf = self; 
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
     UIImage *image = /* render some image */ 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      [weakSelf setImageViewImage:image]; 
     }]; 
    }]; 
    [self.renderQueue addOperation:op]; 

Tất cả các câu trả lời nêu rằng việc sử dụng một tài liệu tham khảo yếu ở đây là không cần thiết, vì mã này không dẫn đến một giữ chu kỳ. Tuy nhiên, trong khi thử nghiệm với một số mã khác, sau đây không dẫn đến một chu kỳ giữ lại (nếu tôi không sử dụng một tài liệu tham khảo yếu, bộ điều khiển xem hiện tại được không deallocated)

//__weak ViewController *weakSelf = self; 
    MBItem *close = [[MBItem alloc] initWithBlock:^{ 
     [self dismissModalWithDefaultAnimation:NO]; 
    }]; 
    NSMutableArray *items = [[NSMutableArray alloc] initWithObjects:close, nil]; 
    [self.childObject setItems:items]; 

Tại sao thứ hai một kết quả trong một chu kỳ giữ lại nhưng không phải là chu kỳ đầu tiên?

+2

Từ khóa là "Giữ lại CYCLE". Như trong, tôi giữ bạn và bạn giữ lại tôi, vì vậy ai cho phép đi đầu tiên? –

Trả lời

12

mã cũ của bạn tạo ra này duy trì chu kỳ nếu bạn không sử dụng __weak:

  • (NSBlockOperation *)op giữ khối ngoài
  • Khối ngoài giữ self (nếu bạn không sử dụng __weak)
  • self giữ lại (NSOperationQueue *)renderQueue
  • (NSOperationQueue *)renderQueue giữ lại (NSBlockOperation *)op

Không có đối tượng nào trong chu kỳ đó có thể được deallocated trừ khi một trong những liên kết đó bị hỏng. Nhưng mã bạn chỉ cho chúng tôi làm phá vỡ chu trình giữ lại. Khi op hoàn thành việc thực thi, renderQueue sẽ giải phóng nó, phá vỡ chu trình giữ lại.

Tôi nghi ngờ rằng mã mới của bạn tạo ra này giữ lại chu kỳ:

  • (MBItem *)close giữ khối
  • Khối giữ self
  • self giữ childObject
  • childObject giữ (NSMutableArray *)items
  • (NSMutableArray *)items giữ (MBItem *)close

Nếu không có gì xảy ra để phá vỡ một trong các liên kết đó, không có đối tượng nào trong chu kỳ có thể được deallocated. Bạn đã không hiển thị cho chúng tôi bất kỳ mã nào phá vỡ chu kỳ lưu giữ. Nếu không có sự kiện nào phá vỡ nó một cách rõ ràng (ví dụ bằng cách xóa childObject.items), thì bạn cần sử dụng __weak để phá vỡ chu kỳ lưu giữ.

8

Tôi không thể cho bạn biết lý do cho chu kỳ lưu giữ trong ví dụ thứ hai của bạn, bởi vì tôi không biết MBItem, nhưng có hai mẫu sử dụng khác nhau với các khối.

Nếu bạn mong đợi khối của bạn để thực hiện trong mọi trường hợp, sau đó bạn chỉ có thể sử dụng self trong khối:

[startSomeOperationWithCompletionBlock:^{ 
    [self doSomeThing]; 
}]; 

Khối giữ một tham chiếu đến self, do đó self không deallocated trước khối là Thực thi. Nhưng sau khi khối đã được thực hiện, tham chiếu này (và chu trình giữ lại) đã biến mất.

Nếu bạn có thể muốn điều đó self được deallocated trước khối đã thực hiện, hoặc nếu nó có thể là các khối sẽ không được gọi là ở tất cả, sau đó bạn phải sử dụng một tham chiếu yếu và kiểm tra giá trị bên trong khối:

__weak MyClass *weakSelf = self; 
[startSomeOperationWithCompletionBlock:^{ 
    MyClass *strongSelf = weakSelf; 
    if (strongSelf) { 
     [strongSelf doSomeThing]; 
    } 
}]; 

khối không giữ lại self trong trường hợp này, do đó self có thể được deallocated. Trong trường hợp đó, weakSelf được đặt thành nil tự động. Vì vậy, nếu khối được thực hiện cuối cùng, bạn phải kiểm tra đầu tiên nếu weakSelf vẫn hợp lệ. (Hoặc bạn chỉ có thể sử dụng nó, bởi vì việc gửi tin nhắn đến nil là không có sẵn.)

Chỉ định một tham chiếu mạnh mẽ self khỏi bị deallocated trong khi khối đang thực thi.

+0

Điều gì xảy ra nếu khối được thực hiện, nhưng nó vẫn đang được giữ trong một số mảng, để nó có thể được sử dụng lại? Tôi đoán bản thân sẽ không được giải quyết ở đây, cho đến khi mảng bị xóa? – Snowman

+0

Vâng, tôi nghĩ đó là những gì @robmayoff đã mô tả trong câu trả lời của anh ấy. –

+0

Tạo một tham chiếu mạnh mẽ đến một con trỏ yếu (hoặc trong trường hợp của tôi __unsafe_unretained) trong khối đã giải quyết được vấn đề tương tự như tôi đã có nơi lớp được deallocated giữa thực hiện của khối. Cảm ơn! – SRandazzo

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