2013-05-16 38 views
5

Tôi có một lớp cơ sở Store với nhiều phương pháp mà tất cả các cửa hàng kế thừa. Mỗi cửa hàng là một singleton. Ngay bây giờ, mỗi cửa hàng định nghĩa riêng gần như giống hệt phương pháp của nó:Mục tiêu-C - bộ khởi tạo đơn động động?

+ (Store *)instance { 
    static SubStore *store = nil; 
    if (!store) { 
     store = (SubStore *) [[super allocWithZone:nil] init]; 
     [store setupDefaults]; 
    } 
    return store; 
} 

Có cách nào đưa ra một phương pháp singleton trong một cách mà phương pháp này chỉ có thể được bổ sung vào lớp cơ sở và được thừa kế bởi các lớp con?

+1

Tôi đã thử và không bao giờ tìm được cách. Ngoài ra, để an toàn cho luồng, bạn nên sử dụng khối 'dispatch_once' thay vì' if (! Store) '. – Kevin

+0

Tôi đã theo dõi mã sách. Tôi sẽ xem xét dispatch_once. –

Trả lời

2

Thay vì sử dụng một cửa hàng static SubStore * store = nil;, bạn có thể sử dụng NSMutableDictionary sử dụng tên lớp làm khóa.

ngắn gọn:

#import <Foundation/Foundation.h> 

@interface MONStore : NSObject 
- (NSString *)nameOfMostPopularItem; 
@end 

@implementation MONStore 

+ (instancetype)sharedStore 
{ 
    // lazy population - not thread safe 
    static NSMutableDictionary * stores = nil; 
    if (nil == stores) { 
     stores = [NSMutableDictionary new]; 
    } 
    NSString * key = NSStringFromClass([self class]); 
    if (nil == [stores objectForKey:key]) { 
     [stores setObject:[self new] forKey:key]; 
    } 
    return [stores objectForKey:key]; 
} 

- (NSString *)nameOfMostPopularItem 
{ 
    return nil; 
} 

@end 

@interface MONMusicStore : MONStore 
@end 

@implementation MONMusicStore 
- (NSString *)nameOfMostPopularItem { return @"Guitar Strings"; } 
@end 

@interface MONPetStore : MONStore 
@end 

@implementation MONPetStore 
- (NSString *)nameOfMostPopularItem { return @"Puppies"; } 
@end 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSLog(@"--- Shopping List ---\nMusic Store:\n\t%@\n\nPet Store:\n\t%@\n", 
        [MONMusicStore sharedStore].nameOfMostPopularItem, 
        [MONPetStore sharedStore].nameOfMostPopularItem 
        ); 
    } 
    return 0; 
} 

... không phải là tôi sẽ bao giờ làm điều này trong chương trình của tôi.

+0

Bạn sẽ sử dụng cái nào thay thế? –

+0

@StefanKendall Tôi là một trong số những kẻ càu nhàu về/không khuyến khích những người độc thân;) – justin

5

Stick với đơn giản/ngu ngốc, nhưng sử dụng dispatch_once.

Ngay sau khi bạn cố gắng làm cho nó chung chung, nó trở nên phức tạp. Và lỗi.

Phương thức sharedInstance với đặt tên lớp rõ ràng đã chết rõ ràng và rất khó bạn sẽ lặp lại nó nhiều lần trong dự án của bạn.

Nếu, tuy nhiên, bạn có nhiều lớp con của một lớp, sau đó chuyển sang mô hình định danh. I E. một bộ nhớ cache trên lớp lưu trữ trừu tượng có thể tìm kiếm các cá thể lưu trữ theo định danh.


Tôi tránh sử dụng +initialize hoặc tệ hơn là +load để khởi tạo như vậy. Cả hai đều không xác định ở chỗ thứ tự thực thi của chúng liên quan đến các hệ thống con khác trong ứng dụng của bạn có thể khá biến đổi với những thay đổi dường như vô hại.

Tốt hơn hết để khởi tạo hoàn toàn xác định. Thêm chú dẫn trong số applicationDidFinishLaunching: (hoặc một trong số những người khác) để khởi tạo rõ ràng hệ thống phụ cụ thể này trong ứng dụng của bạn. Nó rất dễ làm theo, rõ ràng trong cả khai báo và sử dụng, và sẽ không thay đổi hành vi theo những cách kỳ lạ khi codebase của bạn phát triển.

+0

Tôi thường đặt loại mã khởi tạo đó vào '+ khởi tạo'. Thời gian chạy ObjC đảm bảo rằng phương thức này được gọi chỉ một lần. – zneak

+3

@zneak Điều này không hoàn toàn đúng. Nếu bạn có lớp A với phương thức 'initialize' và lớp B mở rộng A và lớp B không thực hiện phương thức' initialize', thì phương thức 'initialize' của lớp A sẽ được gọi hai lần - một lần khi A là đầu tiên được tham chiếu và khi B được tham chiếu lần đầu tiên. – rmaddy

+0

'+ tải' chỉ được gọi một lần cho mỗi lớp/danh mục. – nielsbot

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