2011-10-22 28 views
6

Tôi có bộ điều khiển chế độ xem mà tôi muốn khởi chạy, và sau khi được khởi tạo, hãy sử dụng cùng một bản sao khi có thể (Tôi không sử dụng singleton vì tôi muốn xóa nó khỏi bộ nhớ) , tôi sử dụng getter để làm như vậy, mã của tôi trông như thế này:Chủ đề khởi tạo lười biếng an toàn trên iOS

@property (retain) UIViewController *myController 

... 

@synthesize myController = _myController; 


... 


- (UIViewController *)myController 
{ 
    if (!_myController) {         // Evaluation 
     _myController = [[MyViewController alloc] init]; // Object Creation 
    } 
    return _myController; 
} 

này hoạt động, nhưng nó không phải là thread an toàn, và nếu có nhiều hơn một thread để đánh giá đúng trước khi đối tượng được tạo ra, tôi sẽ phải rò rỉ bộ nhớ. Một giải pháp mà tôi đã thử là @synchronized mã, nhưng tôi không chắc chắn cách chính xác để làm điều đó.

Điều này dường như làm việc, (lockForMyController là một NSString đơn giản) nhưng nó làm cho phần mã này chậm hơn rất nhiều:

- (UIViewController *)myController 
{ 
    @synchronized(self.lockForMyController){ 
     if (!_myController) { 
      _myController = [[MyViewController alloc] init]; 
     } 
    } 
    return _myController; 
} 

tôi đã tự hỏi nếu có một số cách khác để đạt được một lười biếng khởi tạo, chủ đề an toàn, tài sản?

Trả lời

10

giải pháp này hoạt động

Lưu ý rằng giải pháp này chỉ hoạt động nếu MyController được truy cập trên nền sợi lần đầu tiên. Nó sẽ bế tắc nếu được gọi trên sợi chính.

Bạn muốn sử dụng gcd. Điều quan trọng là serialize việc tạo ra các đối tượng, để bất kể các chủ đề bắt đầu từ khối, nó sẽ luôn luôn chỉ được tạo ra chính xác một lần.

- (UIViewController *)myController 
    if (_myController == nil) { 
     dispatch_sync(dispatch_get_main_queue(),^{ if (_myController == nil) _myController = [[MyViewController alloc] init]; }); 
    } 
    return _myController; 
} 

Ở đây, ngay cả khi nhiều luồng thực thi khối, việc thực thi khối được nối tiếp vào chuỗi chính và chỉ có thể tạo một MyViewController.

Bạn sẽ không thấy hiệu suất được truy cập ở đây trừ khi đối tượng là không.

Vì thuộc tính hoàn toàn là nguyên tử, điều đó có nghĩa là trong setter giá trị sẽ được tự động phát hành. Điều này sẽ làm cho nó phù hợp để trộn lẫn với tùy chỉnh của bạn, vì nó sẽ tự động phát hiện bất kỳ thay đổi giá trị nào đối với _myController.

http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW2

Tuy nhiên, bạn vẫn có thể nhận được vào một tình trạng chủng tộc nơi bạn đang thiết lập các giá trị trên một thread nhưng việc tiếp cận nó ngày khác. Bất kỳ lúc nào bạn đặt giá trị, bạn có thể muốn đảm bảo và thực hiện một việc như sau:

dispatch_sync (dispatch_get_main_queue(),^{self.myController = {newValueOrNil}});

Điều này sẽ đảm bảo tuần tự hóa các cuộc gọi phương thức setter của bạn mà không cần phải phát minh lại bánh xe cho các bộ định vị nguyên tử, điều rất khó có được đúng.

Giải pháp này không hoạt động

Bạn muốn sử dụng UCLN.

http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once

Xem bài đăng này về độc thân. Tôi biết bạn không muốn một singleton, nhưng điều này chứng tỏ làm thế nào để sử dụng phương pháp. Bạn có thể dễ dàng điều chỉnh nó.

Create singleton using GCD's dispatch_once in Objective C

+0

Tôi gặp sự cố khi điều chỉnh. Tôi có thể làm cho nó hoạt động như một singleton, nhưng sau đó tôi có vấn đề khi tôi sử dụng '[_myController release]; _myController = nil; 'và sau đó tôi thử tạo lại nó, vì tôi không thể đặt lại biến' static dispatch_once_t once'. – Yamanqui

+0

Hmm cho phép tôi cập nhật câu hỏi của mình với đề xuất sẽ hoạt động. – logancautrell

+0

Cảm ơn bạn rất nhiều, giải pháp cập nhật hoạt động hoàn hảo. – Yamanqui

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