协议方法在类别中实现时无法识别

问题描述:

我有一个必须实现多个协议的视图控制器类。为了保持整洁,我习惯于将每个协议的方法放在视图控制器类的类别中。协议方法在类别中实现时无法识别

这一次我从链接器得到警告,该类没有实现协议之一。这些方法在运行时工作,链接器似乎无法识别类别中的实现。

我在一个不同的项目中简化了类,并且我在同一个地方得到了同样的错误。

类标头:

#import <UIKit/UIKit.h> 
#import <AddressBook/AddressBook.h> 
#import <AddressBookUI/AddressBookUI.h> 

@interface TopVC : UIViewController 
< 
    UINavigationControllerDelegate, 
    ABPeoplePickerNavigationControllerDelegate 
> 
{} 
@end 

的TopVC.m(未示出)是自动生成的,没有变化。该UINavigationControllerDelegate协议方法是这一类中实现:

#import <Foundation/Foundation.h> 
#import "TopVC.h" 

@interface TopVC (UINavigationControllerDelegate) 
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated; 
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;  
@end 

#import "TopVC+UINavigationControllerDelegate.h" 

@implementation TopVC (UINavigationControllerDelegate) 
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{ 
    NSLog(@"navigationController:willShowViewController:animated:"); 
} 

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{ 
    NSLog(@"navigationController:didShowViewController:animated:"); 
} 
@end 

链接器不会抱怨这个方法属于这一类。但是,如果我尝试的类别来实现以相同的方式将ABPeoplePickerNavigationControllerDelegate协议,报告说:

#import "TopVC.h" 

@interface TopVC (ABPeoplePickerNavigationControllerDelegate) 

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker; 

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person; 

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier; 

@end 

#import "TopVC+ABPeoplePickerNavigationControllerDelegate.h" 


@implementation TopVC (ABPeoplePickerNavigationControllerDelegate) 

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{ 

} 

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{ 
    return YES; 
} 

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{ 
    return YES; 
} 
@end 

链接器抱怨:

warning: incomplete implementation of class 'TopVC' 
warning: method definition for '-peoplePickerNavigationController:shouldContinueAfterSelectingPerson:property:identifier:' not found 
warning: method definition for '-peoplePickerNavigationController:shouldContinueAfterSelectingPerson:' not found 
warning: method definition for '-peoplePickerNavigationControllerDidCancel:' not found 
warning: class 'TopVC' does not fully implement the 'ABPeoplePickerNavigationControllerDelegate' protocol 

我能看到的唯一区别是,UINavigationControllerDelegate协议方法所有可选的,而ABPeoplePickerNavigationControllerDelegate都是必需的。

然而,即使链接器抱怨,方法仍然在运行时调用。我只是拒绝建立一个包含警告的构建。我显然错过了一些东西,或者在某个地方犯了一个微不足道的错误,但我无法发现它。

哈!我脑子一片空白。

我忘了协议实现声明移到类的接口,像这样:

#import "TopVC.h" 

@interface TopVC (ABPeoplePickerNavigationControllerDelegateMethods) <ABPeoplePickerNavigationControllerDelegate> 
... 
@end 

这编译没有警告,按预期工作。

我只是懒得使用如此多的可选协议,链接器忽略它,如果它找不到方法实现。

+0

你好,我做了所有像你一样,我得到的错误:'类正在实现一个方法,它也将在其主类'。我做错了什么或者只是这种方式不再相关? – 2014-05-22 00:15:08

通过声明协议,你打算在主接口上实现,编译器希望看到主实现中的方法(关于你声明的是......“它是没有改变的自动生成的方法“)。编译器不知道,你将在一个类别中实现这些方法。所有它知道的是:你“承诺”他们会在那里,但你没有提供他们所期望的。

当编译器正在编译TopVC.m时,它无法知道某个其他文件将提供剩余的所需协议方法。在gcc中,每个.m文件都是独立编译的。你希望将这些东西分成不同的类别是很好的,但所有这些都需要在TopVC.m中实现。

您对TopVC+ABPeoplePickerNavigationControllerDelegate.h中协议方法的重新定义对任何内容都没有影响。 @interface中的特定类别标记与@implementation中的标记之间没有关系。 @interface中的类别定义只是说“这里有一些其他合法的方法可以传递给这个对象而不会产生编译器警告。”这甚至不是创建这种方法的明确承诺。当你表明你符合协议时(这是实现这些方法的承诺),这已经被处理了。

@implementation中的类别定义只是说“这里是这个类的其他方法。”类别标签本身不过是评论。它没有任何关联。

您需要将协议实现移至TopVC.m,并且没有理由拥有TopVC+<protocol>.h文件。如果你想分手你的。m变成单独的@implementation块,这很好,我知道那些做这种事的人。就我个人而言,我只是用#pragma mark来分解这个文件。