2013-06-17 16 views
6

Tôi muốn kế thừa từ một lớp khung công tác có phương pháp nhà máy. Làm thế nào tôi có thể làm cho phương thức factory trả về một đối tượng thuộc kiểu lớp kế thừa của tôi? Tôi tìm thấy this useful article mô tả tình huống tương tự nhưng trong trường hợp của họ, bạn có quyền kiểm soát siêu lớp. Làm thế nào tôi có thể viết, nói, một phân lớp của UIImage rằng imageNamed: sẽ trả về một đối tượng của loại phân lớp của tôi?Thừa kế lớp C mục tiêu với các phương pháp nhà máy

+2

có thể bạn có thể đạt được những gì bạn muốn bằng cách viết một danh mục trên UIImage? –

+0

Vâng, tôi đang nghĩ về hướng này. Chỉ rằng tôi cần một số thành viên lớp bổ sung (thuộc tính) và muốn tránh những rắc rối với objc_setAssociatedObject và bạn bè. Cũng bởi vì tôi không tìm thấy nó thanh lịch để tạo ra một workaround loại này cho một vấn đề hoàn toàn khác nhau. Tuy nhiên tôi sợ nhiều hơn và nhiều hơn nữa mà tôi không có sự lựa chọn. – MrTJ

+1

hãy xem danh mục [NSObject] (https://github.com/pixelflut/PixLib-OpenSource/blob/master/PixLib%20OpenSource/NSObject%2BPixLib.m) này. Hai phương thức 'setRuntimeProperty: name:' ​​và 'runtimeProperty:' giúp thiết lập và truy cập các đối tượng liên quan. –

Trả lời

9

Tôi muốn kế thừa từ lớp khung công tác có phương pháp nhà máy. Làm thế nào tôi có thể làm cho phương thức factory trả về một đối tượng thuộc kiểu lớp kế thừa của tôi?

Đây là tất cả các bạn nên phải làm:

@interface MONImage : UIImage 
@end 

@implementation MONImage 
@end 

Sau đó:

MONImage * image = [MONImage imageNamed:name]; 

Làm thế nào tôi có thể viết, nói, một lớp con của UIImage rằng imageNamed: sẽ trả về một đối tượng thuộc kiểu lớp con của tôi?

+[UIImage imageNamed:] thực hiện đã viết các lớp con ra khỏi phương pháp này. Do đó, bạn sẽ cần phải thực hiện phương pháp này cho mình.

Dưới đây là cách người ta nên khai báo một phương pháp nhà máy:

+ (instancetype)imageNamed:(NSString *)pName; 

và làm thế nào một nên thực hiện nó:

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName]; 
         ^^^^ NOTE: self, not a concrete class 
    ...set up image... 
    return image; 
} 

nhưng họ đã không làm điều đó theo cách đó - +[UIImage imageNamed:] viết phân lớp và trả về một số UIImage khi bạn viết MONImage * img = [MONImage imageNamed:pName];. Đôi khi điều đó được thực hiện vì một lý do chính đáng. Một số phương pháp nên có ngữ nghĩa 'cuối cùng'. Điều này thường xuất hiện khi phương thức của bạn có thể trả về nhiều loại, như trong một nhóm lớp. Ngôn ngữ không thể hiện các phương thức 'cuối cùng' - nhưng một phương pháp như vậy ít nhất phải được ghi lại.


Vì vậy, để đi xung quanh để trường hợp UIImage này:

@interface MONImage : UIImage 

+ (instancetype)imageNamed:(NSString *)pName; 

@end 

@implementation MONImage 

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    UIImage * source = [UIImage imageNamed:pName]; 
    CGImageRef cgImage = source.CGImage; 
    if (cgImage) 
     return [[self alloc] initWithCGImage:cgImage]; 
    // try it another way 
    return nil; 
} 

@end 

Lưu ý rằng UIImage s và CGImage s là không thay đổi. Điều này không nên dẫn đến một bản sao sâu của dữ liệu hình ảnh.

+2

+1 để sử dụng instancetype. – Abizern

+2

thực hiện điều này cũng cung cấp hành vi bộ nhớ đệm của '[UIImage imageNamed:]'? Nếu không, có lẽ bạn nên lưu trữ một tham chiếu đến hình ảnh gốc trong 'MONImage'. Nhưng giải pháp thực sự tốt đẹp. –

+0

@JonathanCichon nó sẽ duy trì hành vi tra cứu của '+ imageNamed:'. nó sẽ tải hình ảnh, sau đó cache nó. hành vi chính xác của việc thực hiện bộ đệm ẩn được tóm tắt để kết luận của tôi là nó không được bảo đảm giống hệt nhau trong vấn đề này. Tôi * giả sử * nó sẽ giống nhau liên quan đến bộ nhớ đệm, nhưng tôi đã không chứng minh điều đó. câu hỏi hay. – justin

2

Ví dụ của bạn:

  • Subclass UIImage đến, nói, MyImage
  • Thực hiện imageNamed: phương pháp để làm bất cứ điều gì cụ thể mà bạn cần phải làm.
  • Gọi rằng phương pháp trên lớp rằng: MyImage *newImage = [MyImage imageNamed:imageName];
+2

Điều này sẽ không thực sự hữu ích, vì bạn không thể gọi 'super' trong việc thực hiện của riêng bạn 'imageNamed', vì điều này sẽ kết thúc trong việc trả về một thể hiện kiểu' UIImage'. –

+0

Ai nói anh ta cần gọi siêu? anh ta có thể phân bổ và khởi tạo một đối tượng của lớp con của mình trong phương thức và trả về nó. Và, như chúng ta đã biết, quy ước là cho các lớp con gọi trình khởi tạo được chỉ định của lớp cha của chúng, trả về một đối tượng kiểu 'id'. Dù sao, đây là một ví dụ contrived dựa trên những gì OP yêu cầu. Các chi tiết được để lại cho người dùng, nhưng nguyên tắc của một hàm tạo thuận tiện phân bổ và bắt đầu một đối tượng của lớp riêng của nó là âm thanh. – Abizern

+1

vâng, nhưng trong trường hợp này, quả táo 'ma thuật' trong 'imageNamed:' rất hữu ích và tôi không nghĩ rằng anh ấy muốn thực hiện điều này một mình. Nhưng bạn là đúng, câu trả lời của bạn không phải là 'sai' nhưng tôi nghĩ rằng không phải là rất hữu ích trong trường hợp này. –

0

Cách tiếp cận đó giải quyết vấn đề của tôi là sử dụng một loại thay cho thừa kế (khoản tín dụng đi đến Jonathan CICHON trong các ý kiến ​​của câu hỏi của tôi). Tôi đã sử dụng Associative References để khai báo và lưu trữ dữ liệu bổ sung trong triển khai danh mục như được thảo luận rất nhiều ở đây trong SO. Tôi muốn hướng sự chú ý đến số NSObject category implementation được Jonathan đề xuất, điều này thực sự dễ dàng và thanh lịch để thêm các tham chiếu liên kết vào bất kỳ đối tượng nào.

+0

Trong khi tôi vui vì bạn đã giải quyết được vấn đề của mình - câu hỏi của bạn là về các nhà xây dựng thuận tiện, mà sau đó bạn đã thay đổi thành câu hỏi về cách thêm dung lượng vào một lớp bên ngoài phần mở rộng của lớp. Vì vậy, thực sự có hai bộ câu hỏi và câu trả lời đang diễn ra cùng một lúc. – Abizern

+0

Tôi cần mở rộng lớp khung ban đầu với dữ liệu bổ sung và vẫn có thể sử dụng các nhà xây dựng tiện lợi ban đầu của nó. Khi tôi hỏi câu hỏi ban đầu tôi không có ý tưởng làm thế nào để làm điều này và cho rằng nó có thể đạt được với thừa kế. Bạn đúng từ quan điểm mà tôi đã không chỉ định chính xác rằng tôi cần thêm dữ liệu bổ sung vào lớp, nhưng đã viết "thừa kế". Mặt khác, giải pháp của Jonathan hoàn toàn giải quyết vấn đề của tôi ngay cả khi không sử dụng thừa kế. – MrTJ

+0

NB: Tôi không thay đổi câu hỏi gốc và thêm gợi ý của assoc.refs trong câu trả lời này chỉ làm tài liệu tham khảo cho người đọc trong tương lai. – MrTJ