2012-04-08 9 views
5

Tôi đã tìm thấy mẫu đơn trên mạng. Dường như với tôi nó có nhiều thứ có thể được tối ưu hóa.Mục tiêu-C - Tối ưu hóa mẫu đơn này?

-In sharedMySingleton phương pháp, không cần phải giữ lại? Tôi không chắc chắn ...
-Nếu không, tại sao lại giữ lại trong allocWithZone?
-khi sử dụng @synchronized. NSAssert nghĩ rằng khối có thể được gọi nhiều lần, vì vậy nếu có, sẽ có thêm một số mã để giải phóng bộ nhớ trước đó, hoặc thoát khỏi khối rõ ràng mà không cần NSAsserting, và nếu không, tại sao lại có NSAssert này?
-giây xích giữa sharedMySingletonalloc có vẻ lạ. Tôi muốn viết bản thân mình một cái gì đó như:

+(MySingleton*)sharedMySingleton 
{ 
    @synchronized([MySingleton class]) 
    { 
     if (_sharedMySingleton == nil) _sharedMySingleton = [[self alloc] init]; 
     return _sharedMySingleton; 
    } 

    return nil; 
} 

+(id)alloc 
{ 
    @synchronized([MySingleton class]) 
    { 
     return [super alloc]; 
    } 

    return nil; 
} 

Singleton pattern

#import "MySingleton.h" 

@implementation MySingleton 

// ########################################################################################################## 
// ######################################## SINGLETON PART ################################################## 
// ########################################################################################################## 
static MySingleton* _sharedMySingleton = nil; 

// ================================================================================================= 
+(MySingleton*)sharedMySingleton 
// ================================================================================================= 
{ 
    @synchronized([MySingleton class]) 
    { 
     if (_sharedMySingleton == nil) [[self alloc] init]; 
     return _sharedMySingleton; 
    } 

    return nil; 
} 

// ================================================================================================= 
+(id)alloc 
// ================================================================================================= 
{ 
    @synchronized([MySingleton class]) 
    { 
     NSAssert(_sharedMySingleton == nil, @"Attempted to allocate a second instance of a singleton."); 
     _sharedMySingleton = [super alloc]; 
     return _sharedMySingleton; 
    } 

    return nil; 
} 

+ (id)allocWithZone:(NSZone *)zone { return [[self sharedMySingleton] retain]; } 
- (id)copyWithZone:(NSZone *)zone { return self; } 
- (id)retain      { return self; } 
- (NSUInteger)retainCount   { return NSUIntegerMax; /* denotes an object that cannot be released */} 
- (oneway void)release    { /* do nothing */ } 
- (id)autorelease     { return self; } 

// ########################################################################################################## 
// ########################################################################################################## 
// ########################################################################################################## 

// ================================================================================================= 
-(id)init 
// ================================================================================================= 
{ 
    if (!(self = [super init])) return nil; 

    return self; 
} 

// ================================================================================================= 
-(void) dealloc 
// ================================================================================================= 
{ 
    [super dealloc]; 
} 

// ================================================================================================= 
-(void)test 
// ================================================================================================= 
{ 
    NSLog(@"Hello World!"); 
} 

@end 

Trả lời

17

Bạn không nên sử dụng mô hình này ở tất cả (đó là một trường hợp rất đặc biệt của Singleton mà bạn hầu như không bao giờ cần, và ngay cả trong trường hợp đó bạn thường không nên sử dụng nó).

Có nhiều mẫu tốt được thảo luận tại What should my Objective-C singleton look like?, nhưng hầu hết chúng đều lỗi thời kể từ khi phát hành GCD. Trong các phiên bản hiện đại của Mac và iOS, bạn nên sử dụng các mô hình sau đây, được đưa ra bởi Colin Barrett trong câu hỏi liên quan:

+ (MyFoo *)sharedFoo 
{ 
    static dispatch_once_t once; 
    static MyFoo *sharedFoo; 
    dispatch_once(&once, ^{ sharedFoo = [[self alloc] init]; }); 
    return sharedFoo; 
} 

tôi chỉ sao chép nó ở đây chứ không phải là đánh dấu các câu hỏi lặp lại bởi vì câu trả lời cao nhất đánh giá câu hỏi cũ của đã lỗi thời.

+0

Còn các phương pháp khác: giữ lại, giữ lại, phát hành, copyWithZone, ...? Tại sao bạn lại nói về các phiên bản "hiện đại"? Bạn có ý nghĩa gì bởi hiện đại? Bất kỳ ý tưởng nào về việc tại sao Apple không cập nhật đoạn mã đơn lẻ của mình bằng loại mã này? – Oliver

+1

Bởi hiện đại, tôi có nghĩa là kể từ khi giới thiệu của GCD. Bạn không nên ghi đè lên các phương pháp này. Mã mẫu duy nhất cho thấy ghi đè những điều này là ở đây: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html Vì nó lưu ý, đây là triển khai * nghiêm ngặt * của singleton, mà văn bản ở trên giải thích nói chung là không cần thiết. Tôi đã mở một trường hợp tài liệu để cải thiện tài liệu này vì nó bị nhầm lẫn rất nhiều nhà phát triển. Mike Ash có một bài đăng hay về điều này: http://www.mikeash.com/pyblog/friday-qa-2009-10-02-care-and-feeding-of-singletons.html –

+0

Tương đương với 10,6 trong điều khoản của iOS? – Oliver

0

Không cần gọi retain vì có alloc. Gọi số retain trên đó sẽ gây ra rò rỉ bộ nhớ. Có giữ lại trên allocWithZone bởi vì nó là một singleton, vì vậy chúng tôi không muốn tạo ra hai trường hợp khác nhau của lớp. Thay vì phân bổ một thể hiện mới, chúng tôi tăng số lượng giữ lại của cá thể singleton. Tại sao vậy? Có lẽ để ngăn chặn ai đó không nhận thức được loại singleton của lớp. Nếu anh ta gọi allocWithZone và sau đó phát hành cá thể, mọi thứ vẫn hoạt động tốt và anh ta thực sự truy cập vào cá thể singleton được chia sẻ.

@synchronized được sử dụng để ngăn hai cuộc gọi từ hai luồng khác nhau nhập vào câu lệnh if cùng một lúc. Vì vậy, mã là an toàn thread.

NSSAssert có thể khiến ứng dụng 'bị lỗi' nếu hai phiên bản của singleton được tạo ra. Đó là mã 'just-to-be-sure', còn được gọi là lập trình phòng thủ.

Liên quan đến chuỗi giữa các số sharedMySingletonalloc, tôi nghĩ nó ổn.

0

Trong phương thức chia sẻ MySingleton, không cần phải giữ lại?

alloc trả về phiên bản mới với số tham chiếu một, vì vậy không cần giữ lại.

Nếu không, tại sao lại giữ lại trong allocWithZone?

Theo quy tắc, khi bạn gọi allocWithZone, bạn sở hữu tham chiếu, do đó, tăng số lượng tham chiếu cho bạn. Nhưng điều này thực hiện allocWithZone là trở về singleton dụ đã được tạo ra và thuộc sở hữu của người khác (phương pháp sharedMySingleton). Vì vậy, phương thức sharedMySingleton tạo đối tượng với alloc, do đó nó trở thành chủ sở hữu. Và sau đó bạn nhận được cùng một trường hợp thông qua allocWithZone, do đó bạn trở thành một chủ sở hữu thứ hai của cùng một trường hợp. Vì vậy, số lượng giữ lại phải tăng lên kể từ khi có hai chủ sở hữu bây giờ. Đó là lý do tại sao allocWithZone cần giữ lại.

Việc sử dụng @synchronized là gì?

@synchronized cho phép mã được gọi đồng thời bởi nhiều chuỗi. Nếu bạn sẽ không bao giờ gọi sharedMySingleton từ nhiều hơn một chủ đề thì không cần thiết và bạn có thể bỏ qua nó.

Các NSAssert làm nghĩ rằng khối có thể được gọi nhiều lần, vì vậy nếu vâng, cần có một số mã khác để giải phóng bộ nhớ trước đó, hoặc thoát khối rõ ràng không chỉ NSAsserting, và nếu không, tại sao là có NSAssert này không?

Do lớp học được dự định là đơn lẻ nên chỉ nên gọi một lần là alloc. NSAssert() chấm dứt chương trình nếu alloc được gọi nhiều lần. Vì NSAssert() chấm dứt chương trình, khi alloc được gọi là lần thứ hai, không cần quản lý bộ nhớ.