Hãy chắc chắn rằng bạn đọc tham luận về câu hỏi này/câu trả lời, quá. Why should we separate alloc and init calls to avoid deadlocks in Objective-C?
Để mở rộng vấn đề điều kiện chủng tộc; sửa đổi thực là không có sự khởi tạo không xác định trong ứng dụng của bạn. Không xác định hoặc lười biếng kết quả khởi trong hành vi đó có thể dễ dàng thay đổi do sự thay đổi có vẻ vô hại - cấu hình, "không liên quan" thay đổi mã, vv ...
Tốt hơn để khởi tạo một cách rõ ràng hệ thống con vào một điểm nổi tiếng-tốt trong tuổi thọ của chương trình. I E. thả [MyClass sharedInstance];
vào phương thức applicationDidFinishLaunching:
của đại biểu ứng dụng nếu bạn thực sự cần hệ thống con được khởi tạo sớm trong chương trình (hoặc di chuyển nó sớm hơn, nếu bạn muốn phòng thủ thêm).
Vẫn còn tốt hơn để di chuyển khởi tạo hoàn toàn khỏi phương thức đó. I E. [MyClass initializeSharedInstance];
trong đó +sharedInstance
xác nhận() nếu phương thức đó không được gọi trước.
Nhiều như tôi là một người hâm mộ tiện lợi, 25 năm lập trình ObjC đã dạy tôi rằng khởi tạo lười biếng là nguồn cung cấp bảo trì và tái cấu trúc hơn những vấn đề đau đầu.
Trong khi tình trạng chủng tộc mô tả dưới đây tồn tại, mã này không sửa chữa những gì được mô tả dưới đây. Nó đã làm cho một vài thập kỷ khi chúng tôi không lo lắng về concurrency trong initializers dụ chia sẻ. Để lại mã sai cho sự thịnh vượng.
Hãy nhớ rằng đối với cả hai câu trả lời chính xác của Colin và Harald, có một điều kiện đua rất tinh tế có thể dẫn bạn đến một thế giới của sự khốn khổ.
Cụ thể, nếu -init
của lớp đang được phân bổ xảy ra, hãy gọi phương thức sharedInstance
, nó sẽ làm như vậy trước khi biến được đặt. Trong cả hai trường hợp, nó sẽ dẫn đến bế tắc.
Đây là lần bạn muốn tách phân bổ và init. Cribbing đang Colin vì nó là giải pháp tốt nhất (giả sử Mac OS X):
+(MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t pred;
// partial fix for the "new" concurrency issue
if (sharedInstance) return sharedInstance;
// partial because it means that +sharedInstance *may* return an un-initialized instance
// this is from https://stackoverflow.com/questions/20895214/why-should-we-separate-alloc-and-init-calls-to-avoid-deadlocks-in-objective-c/20895427#20895427
dispatch_once(&pred, ^{
sharedInstance = [MyClass alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
lưu ý này chỉ hoạt động trên Mac OS X; Đặc biệt là X 10.6+ và iOS 4.0+.Trên các hệ điều hành cũ hơn, nơi các khối không có sẵn, hãy sử dụng khóa hoặc một trong các phương tiện khác nhau để làm điều gì đó một khi không phải là khối dựa.
Mẫu trên không thực sự ngăn chặn sự cố được mô tả trong văn bản và sẽ gây ra bế tắc khi gặp phải. Vấn đề là dispatch_once()
không được tái nhập và do đó, nếu init
gọi sharedInstance
, thành phố wedge.
Bạn có thể quan tâm đọc bài viết này (http: //steve.yegge. googlepages.com/singleton-considered-stupid). – sand
Mặc dù ghét của yegge cho người độc thân, họ chắc chắn máy chủ một mục đích trên iPhone. Nhưng nếu bạn chỉ đơn giản là tạo một 'không gian tên', hãy sử dụng các phương thức lớp thay thế. – bentford
@bentford - Tôi đã lập trình iPhones được 4 năm, mã cũ và mới. Tôi đã từng nhìn thấy các single được sử dụng một lần (trong một số mã khá tệ hại). –