2009-07-06 25 views
46

Khi sử dụng loại, bạn có thể ghi đè lên các phương pháp thực hiện với riêng bạn như vậy:Ghi đè phương thức qua Danh mục ObjC và gọi triển khai mặc định?

// Base Class 
@interface ClassA : NSObject 
- (NSString *) myMethod; 
@end 
@implementation ClassA 
- (NSString*) myMethod { return @"A"; } 
@end 

//Category 
@interface ClassA (CategoryB) 
- (NSString *) myMethod; 
@end 
@implementation ClassA (CategoryB) 
- (NSString*) myMethod { return @"B"; } 
@end 

Gọi phương thức "myMethod" sau bao gồm các loại lưới kết quả "B".

Cách dễ nhất cho việc triển khai Danh mục myMethod để gọi lớp A myMethod ban đầu là gì? Như gần như tôi có thể tìm ra, bạn phải sử dụng các cuộc gọi cấp thấp để có được móc phương thức ban đầu cho Class A và gọi nó, nhưng nó có vẻ như sẽ có một cách dễ dàng hơn về cú pháp để làm điều này.

Trả lời

36

Nếu bạn muốn một cách hackish để làm điều này liên quan đến việc mucking với thời gian chạy mục tiêu c bạn luôn có thể sử dụng method swizzling (chèn tuyên bố từ chối tiêu chuẩn ở đây.) để lưu trữ các phương thức khác nhau như arbitrariliy có tên là selectors, sau đó hoán đổi chúng trong thời gian chạy khi bạn cần chúng.

+10

Nó không nhất thiết là một cách 'hack'. Thời gian chạy Objective-C có lý do. Đó là những gì làm cho Objective-C vượt trội so với các ngôn ngữ biên dịch khác. –

+0

Dựa trên kinh nghiệm của tôi, cắt theo đuổi, bạn muốn sử dụng JRSwizzle, như đã đề cập trong liên kết ở trên. Nó được chống đạn cho tôi. –

+3

Liên kết với mã JRSwizzle: https://github.com/rentzsch/jrswizzle… Tôi đã đến để yêu thích điều này, phương pháp swizzling là rất mạnh mẽ bất cứ khi nào bạn muốn tinh chỉnh một thư viện bên thứ 3 để làm như bạn vui lòng! – LearnCocos2D

19

Từ comp.lang.objective-C FAQ listing:?. "gì nếu nhiều loại thực hiện các phương pháp tương tự Sau đó vải của vũ trụ như chúng ta biết nó không còn tồn tại thực tế, đó không phải là hoàn toàn đúng, nhưng chắc chắn một số vấn đề sẽ được gây ra Khi a. thể loại thực hiện một phương thức đã xuất hiện trong một lớp (cho dù thông qua một thể loại khác, hoặc lớp chính @implementation), định nghĩa của danh mục đó sẽ ghi đè định nghĩa đã có trước đó. Lưu ý rằng nếu hai loại ghi đè lên cùng một phương thức thì tùy theo điều kiện nào được tải "thắng" cuối cùng, điều này có thể không được dự đoán trước khi mã được khởi chạy. "

Từ developer.apple.com: "Khi danh mục ghi đè phương pháp được kế thừa, phương pháp trong danh mục có thể, như thường lệ, gọi triển khai kế thừa qua thư đến siêu. Tuy nhiên, nếu danh mục ghi đè phương thức đã tồn tại trong danh mục class, không có cách nào để gọi thực hiện ban đầu "

+0

Đúng, điều này thực sự không được ngôn ngữ hỗ trợ. – Chuck

+0

Tôi cảm ơn bạn đã bình luận, nhưng tôi đang tìm cách nó có thể được thực hiện (bởi vì tôi biết nó có thể được, chỉ cần không dễ dàng) không phải như thế nào là không thể ... –

+0

Tôi nghĩ rằng 'super' nên giải quyết đối tượng gốc. Xét cho cùng, danh mục giống như một lớp con (ví dụ: bạn có thể ghi đè lên các phương thức). –

12

Kiểm tra bài viết của tôi về một giải pháp được tìm thấy trên thư viện cho nhà phát triển Mac: http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html

Về cơ bản, nó giống như ở trên Phương pháp Swizzling với một ví dụ ngắn gọn:

 
#import <objc/runtime.h> 

@implementation Test (Logging) 

- (NSUInteger)logLength { 
    NSUInteger length = [self logLength]; 
    NSLog(@"Logging: %d", length); 
    return length; 
} 

+ (void)load { 
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(length)), class_getInstanceMethod(self, @selector(logLength))); 
} 

@end 
1

Với swizzling " helper "các phương thức được bao gồm trong ConciseKit, bạn thực sự gọi triển khai mặc định ... đủ kỳ lạ .. bằng cách gọi thực hiện SWIZZLED của bạn ..

Bạn đặt nó lên trong + (void) load, gọi + (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;, tức là

[$ swizzleMethod:@selector(oldTired:) 
      with:@selector(swizzledHotness:) in:self.class]; 

và sau đó trong phương pháp swizzled .. chúng ta hãy giả sử nó trả -(id) .. bạn có thể làm nghịch ngợm của bạn, hoặc bất cứ lý do bạn đang swizzling trong lần đầu tiên đặt ... và sau đó, thay vì trả lại một đối tượng, hoặc self, hoặc không có điều gì ..

return [self swizzledHotness:yourSwizzledMethodsArgument]; 

As explained here…

Trong phương pháp này, có vẻ như chúng ta đang gọi cùng một phương thức một lần nữa, gây ra và đệ quy vô tận. Nhưng vào thời điểm dòng này đạt tới hai phương pháp đã được hoán đổi. Vì vậy, khi chúng tôi gọi swizzled_synchronize, chúng tôi thực sự đang gọi phương thức gốc.

Cảm giác có vẻ lạ, nhưng .. nó hoạt động. Điều này cho phép bạn thêm phần tô điểm bất tận vào các phương thức hiện có, và vẫn "gọi siêu" (thực sự là tự) và gặt hái những lợi ích của công việc của phương thức gốc ... ngay cả khi không truy cập nguồn gốc.

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