2012-08-06 30 views
7

Tôi mới trong Objective-C và tôi đang cố gắng tạo một lớp singleton dựa trên Apple's documentation.super allocWithZone có một số nghi ngờ trong khái niệm lớp singleton

+ (MyGizmoClass*)sharedManager 
{ 
    if (sharedGizmoManager == nil) { 
     sharedGizmoManager = [[super allocWithZone:NULL] init]; 
    } 
    return sharedGizmoManager; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    return [[self sharedManager] retain]; 
} 

Trong mã này sharedManager là phương pháp tĩnh sẽ kiểm tra xem đối tượng của lớp này có mặt không. Nếu vậy nó sẽ trả về đối tượng đã tạo trước đó, nếu không nó sẽ tạo một đối tượng mới.

Tôi có một số câu hỏi sau:

  1. Nếu sharedManager là tĩnh, làm thế nào có thể nó để truy cập super?

  2. Khi tôi in [super class] tại sao nó cung cấp tên lớp hiện tại?

  3. Tại sao [[super allocWithZone:NULL] init] trả về đối tượng lớp hiện tại?

  4. Nếu super bằng self ở đây lý do tại sao số điện thoại hiện tại không gọi là allocWithZone:(NSZone *)zone?

+0

Bạn có thể xem [bài đăng trước đây của tôi về triển khai mẫu đơn lẻ] (http://stackoverflow.com/questions/6912703/objective-c-static-field-and-implementing-singleton-pattern/6913036#6913036). Nếu đã đặt rất nhiều nhận xét trong mã triển khai. Hy vọng điều này sẽ giúp –

+0

Tại sao bạn phân bổ siêu? Bạn không muốn một thể hiện của bản thân để thay thế? –

+0

Đó là một tài liệu cũ đáng kinh ngạc. –

Trả lời

3

Các câu trả lời khác, mặc dù họ chỉ ra thông tin tốt liên quan đến người độc thân, đã không thực sự trả lời câu hỏi của bạn.Câu hỏi của bạn thực sự chủ yếu dựa trên hướng đối tượng, thực tế là bạn đặc biệt tham khảo một singleton là ngẫu nhiên.

  1. Tôi đã trả lời this question với tham chiếu đến self, đây là diễn giải, một phần quan trọng của câu trả lời

    super không có ý nghĩa trong bối cảnh mức lớp, nhưng nó đề cập đến cha chính nó, không phải là một ví dụ

  2. Điều này cũng khiến tôi không thích. Tôi hỏi this question và nó đã kết luận:

    [super class] gọi phương thức super trên dụ hiện tại (ví dụ: self). Nếu bản thân có một phiên bản ghi đè, thì nó sẽ được gọi và nó sẽ trông khác. Vì bạn không ghi đè lên, hãy gọi số [self class] giống như gọi số [super class].

  3. Bạn có chắc chắn nó thực sự trả lại một phiên bản của lớp này không? Hay bạn đang gán nó cho một cá thể sharedGizmoManager của lớp này?

  4. Siêu không bằng tự, nhưng một số phương pháp bạn đã gọi: ví dụ: [super class] đang gọi cùng một cách thực hiện phương thức mà [self class] sẽ gọi.

+2

Tôi nghĩ rằng # 2 bỏ dấu. siêu, một * từ khóa * mà không thể được ghi đè, gửi tin nhắn đến siêu lớp. Trong một phương thức tĩnh + (không phải là các phương thức tĩnh thực sự mà là các phương thức động của các lớp * Lớp *), lớp cha là một * NSObject *. * Phương thức * class * của NSObject * khi được gọi với 'super' trả về lớp con, vì vậy' [self class] == [super class] 'trong một phương thức tĩnh. –

+0

Việc triển khai NSObject trông giống như sau: Lớp '+ (Lớp) { trả lại tự; } '- ' self' trong trường hợp này, là phân lớp, vì đó là nơi bạn đang gửi thư từ đó. '+ (Class) superclass' sẽ có hiệu ứng mong muốn, trong trường hợp bạn muốn' [self superclass]; '(note + method). – Ephemera

+0

@RiazRizvi, Vui lòng sửa đổi câu trả lời! –

3

Có một vài điều cần xem xét ở đây. Đầu tiên, hướng dẫn về Nguyên tắc cơ bản về ca cao có phần lỗi thời. Nó không tính đến một số công nghệ hiện tại mà Apple đã phát triển, như Grand Central Dispatch và Automated Reference Counting. [Giữ lại] trong phương thức allocWithZone của bạn sẽ không biên dịch chính xác trong một dự án có hỗ trợ ARC (vì bạn mới sử dụng Obj-C, tôi đang tạo một giả định ở đây bạn cũng mới sử dụng iOS/iPhone, và vì vậy bạn nên đọc về hai công nghệ đó).

Có một cuộc thảo luận rất tốt của các mẫu thiết kế khác nhau singleton qua trong luồng này: What should my Objective-C singleton look like?

Tuy nhiên đó là một chủ đề lớn hơn, và như vậy không đưa vào tài khoản tự động đếm tham chiếu (Tôi đã sử dụng Louis Câu trả lời của Gerbang trong nhiều năm và nó không còn hoạt động trong các dự án hỗ trợ ARC nữa).

Đối với ARC-enabled dự án/file (có ARC có thể được kích hoạt chỉ cho các tập tin duy nhất) - chúng tôi đã chuyển đến một singleton sử dụng GCD và hoạt động khá tốt:

static YourClassName * volatile sharedInstance = nil; 

+ (YourClassName *)sharedInstance 
{ 
    static dispatch_once_t sharedInstanceToken; 
    dispatch_once(&sharedInstanceToken, ^{ 
     sharedInstance = [[YourClassName alloc] init]; 
    }); 
    return sharedInstance; 
} 

gì đang xảy ra ở đây? Vâng, nếu bạn xem qua GCD docs, bạn sẽ thấy dispatch_once chỉ được thực thi một lần trong suốt toàn bộ thời gian tồn tại của một ứng dụng cho một đối tượng cụ thể. Theo các tài liệu đi vào nói, điều này làm cho nó rất hữu ích cho việc tạo ra singletons một cách an toàn thread.

Trên hết, chúng tôi khai báo phương thức sharedInstance là dễ bay hơi, nghĩa là trình biên dịch/thời gian chạy sẽ không bao giờ cố gắng lưu lại cuộc gọi đến phương thức và phải luôn thực thi mã bên trong. Điều này làm cho chắc chắn rằng chúng tôi luôn luôn gọi vào GCD và chúng tôi luôn luôn lấy lại các đối tượng mà chúng tôi đang phải.

Tôi đang tô bóng trên một nhóm vì bạn mới sử dụng Obj-C, nhưng chắc chắn hãy xem xét GCD, ARC và sau đó khi bạn đã có nền tảng vững chắc trong Obj-C, hãy xem IMP caching , đó là những gì dễ bay hơi đang ngăn cản xảy ra.

+0

câu trả lời tuyệt vời, gần đây tôi đã chuyển sang cách tạo ra những người độc thân, nhưng tôi chưa bao giờ nghe nói về từ biến động! –

+0

Mặc dù bạn cung cấp thông tin tốt về người độc thân, họ chỉ nghi ngờ họ tham khảo. Câu hỏi thực sự là về oop và việc thực hiện các phương thức nào được gọi. –

+3

"chúng tôi khai báo phương thức sharedInstance là biến động" - Nhưng bạn đang khai báo biến tĩnh biến động, không phải phương thức. Các phương thức dễ bay hơi không tồn tại trong Objective-C và các cuộc gọi phương thức không bao giờ được tối ưu hóa. Thay vào đó, bạn nên di chuyển biến tĩnh bên trong phương thức. Điều đó đảm bảo nó không bao giờ được truy cập mà không cần gọi phương thức. – nschum

3

(1.) super trong 'hàm tĩnh' là gì? Trong các phương thức Objective-C, + được gọi đúng là các phương thức lớp, -methods được gọi là các phương thức ví dụ. Các phương thức + này không phải là phương thức tĩnh thực sự vì Objective-C classes are themselves objects of an opaque type called Class. Vì vậy, cả hai superself được xác định trong + phương pháp. super gửi tin nhắn đến siêu lớp của MyGizmoClass, nhưng khi được gọi từ phương thức + super tìm kiếm một phương thức + tương đương và khi được gọi từ một phương thức -method super tìm kiếm phương thức tương ứng.
self trong các phương pháp + của MyGizmoClass trả MyGizmoClass mà là một Lớp, trong khi ở -methods self là một con trỏ đến một MyGizmoClass dụ.

(2.) Phương thức +class trả về self.isa. Có [super class] gọi phương thức của lớp cha:+class, tuy nhiên, khi self được chuyển đến + phương thức, giá trị của nó cũng không được sửa đổi (trong khi loại self được truyền tới siêu lớp khi được truyền qua -methods). Vì vậy, khi triển khai phương pháp +class lên chuỗi yêu cầu self.isa, nó sẽ có cùng giá trị, MyGizmoClass.
Để chắc chắn, bạn có thể xác minh rằng super không gọi +class trong superclasses bằng cách bắt nguồn MyGizmoClass từ một MyGizmoSuperClass nơi bạn có thể đặt một ghi đè:

@interface MyGizmoSuperClass : NSObject 
    @end 
    @implementation MyGizmoSuperClass 
    +(Class) class { 
     NSLog(@"yes it calls MyGizmoSuperClass:class"); 
     return [super class]; 
    } 
    @end 
    @interface MyGizmoClass : MyGizmoSuperClass 
    +(Class) classviasuper; 
    @end 
    @implementation MyGizmoClass 
    +(Class) classviasuper { 
     return [super class]; //which version of class will super call? 
    } 
    @end 
    int main(int argc, char *argv[]) 
    { 
     NSLog(@"returned %@",[MyGizmoClass classviasuper]); 
    } 

in

có nó gọi MyGizmoSuperClass: class
trả lại MyGizmoClass

(3.) Một lần nữa super gọi là phiên bản lớp cha của allocWithZone nhưng self giá trị truyền cho phương pháp này vẫn trỏ đến một MyGizmoClass, và kể từ allocWithZone trả về một đối tượng của lớp của người nhận, bạn nhận được một MyGizmoClass quay lại.

(4.) Bạn có thể dễ dàng xác minh super khác với self. Nếu bạn triển khai [self allocWithZone:NULL] mã của bạn sẽ gọi số MyGizmoClass triển khai allocWithZone và lặp vô thời hạn. Với [super allocWithZone:NULL], phiên bản của lớp cha được gọi.