2009-06-22 41 views
10

Tôi có hai lớp có thể hoạt động như một đại biểu của một lớp thứ ba và cả hai thực hiện một giao thức chính thức được thực hiện hoàn toàn bằng các phương thức tùy chọn. Một trong các lớp thực hiện mọi thứ trong khi một lớp khác chỉ thực hiện một vài phương thức mà tôi quan tâm. Tuy nhiên, vào thời gian chạy khi tôi có lớp thứ hai hoạt động như ủy nhiệm cho lớp thứ ba, và lớp thứ ba kết thúc lên gọi một trong các phương thức tùy chọn chưa được thực hiện trên đại biểu đó, tôi nhận được lỗi thời gian chạy về cơ bản nói "Mục tiêu không phản hồi điều này bộ chọn tin nhắn. " Tôi nghĩ rằng mục tiêu-c xử lý trường hợp này một cách chính xác, và rằng nó sẽ chỉ làm gì nếu phương pháp đó đã không thực sự được xác định trên lớp. Có thể có một cái gì đó tôi đang mất tích?Tại sao các phương thức giao thức tùy chọn chưa thực hiện gây ra lỗi thời gian chạy khi phương thức đó được gọi trong obj-c?

Trả lời

33

Khi bạn gọi một phương pháp bắt buộc của đại biểu của bạn, bạn cần phải chắc chắn rằng nó phản ứng với bộ chọn trước khi gọi nó:

if ([delegate respondsToSelector:@selector(optionalMethod)]) 
    [delegate optionalMethod]; 
+2

Tôi nghi ngờ càng nhiều, nhưng tôi đã hy vọng tôi sẽ không cần phải thêm những if-kiểm tra trên tất cả các mã. Cảm ơn con trỏ. – Kevlar

10

phương pháp giao thức bắt buộc chỉ đơn giản có nghĩa là các đối tượng thực hiện các giao thức không nhất thiết phải thực hiện phương pháp được đề cập - callee sau đó hoàn toàn phải kiểm tra xem đối tượng có thực hiện phương thức trước khi gọi hay không (nếu không bạn sẽ gặp sự cố, như bạn đã thấy). Những loại NSObject HOM có thể hữu ích:

@implementation NSObject (Extensions) 

- (id)performSelectorIfResponds:(SEL)aSelector 
{ 
    if ([self respondsToSelector:aSelector]) { 
     return [self performSelector:aSelector]; 
    } 
    return NULL; 
} 

- (id)performSelectorIfResponds:(SEL)aSelector withObject:(id)anObject 
{ 
    if ([self respondsToSelector:aSelector]) { 
     return [self performSelector:aSelector withObject:anObject]; 
    } 
    return NULL; 
} 

@end 

Sau đó, bạn chỉ đơn giản có thể làm:

[delegate performSelectorIfResponds:@selector(optionalMethod)]; 
+0

đề xuất tốt đẹp :) – Kevlar

+0

........ Whats HOM? – bandejapaisa

+0

HOM = Nhắn tin đặt hàng cao hơn. –

1

Blocks có thể cung cấp một giải pháp tốt hơn. Chúng cho phép để có điều kiện thực hiện bất kỳ mã dựa trên sự tồn tại của một thực hiện một phương pháp đưa ra:

-(void) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector{ 
    if ([self respondsToSelector:aSelector]) { 
     block(); 
    } 
} 

Bằng việc sử dụng bổ sung này để NSObject, bạn có điều kiện có thể thực hiện bất kỳ phương pháp @optional, dù có bao nhiêu thông số nó có thể có .

Xem How to safely send @optional protocol messages that might not be implemented

4

giải pháp Blocks này hoạt động tốt, một khi bạn nhận được đầu của bạn quấn quanh những gì đang xảy ra. Tôi đã thêm một kết quả BOOL vì tôi muốn có thể điều kiện chạy một trong một số phương pháp tùy chọn. Một số mẹo nếu bạn đang cố triển khai giải pháp này:

Trước tiên, nếu bạn chưa gặp phải Tiện ích mở rộng/Danh mục, bạn chỉ cần thêm phần này vào đầu lớp học của mình, NGOÀI định nghĩa lớp hiện tại. Nó sẽ là một phần mở rộng công cộng hoặc riêng dựa trên nơi bạn đặt nó.

@implementation NSObject (Extensions) 
// add block-based execution of optional protocol messages 
-(BOOL) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector 
{ 
    if ([self respondsToSelector:aSelector]) { 
     block(); 
     return YES; 
    } 
    return NO; 
} 
@end 

Thứ hai, đây là cách bạn gọi nó là từ mã của bạn:

BOOL b = [(NSObject*)self.delegate performBlock:^{ 
    // code to run if the protocol method is implemented 
} 
ifRespondsTo:@selector(Param1:Param2:ParamN:)]; 

Thay Param1: param2: ParamN: với tên của mỗi tham số cho phương pháp giao thức của bạn. Mỗi người nên kết thúc bằng dấu hai chấm. Vì vậy, nếu phương pháp giao thức của bạn trông giống như:

-(void)dosomething:(id)blah withObj:(id)blah2 andWithObj(id)blah3;

dòng cuối cùng sẽ trông như thế này:

ifRespondsTo:@selector(dosomething:withObj:andWithObj:)];

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