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

时间:2010-03-06 00:16:24

标签: iphone objective-c protocols xcodebuild categories

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

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

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

班级标题:

#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都是必需的。

然而,即使链接器抱怨,这些方法仍然在运行时调用。我只是拒绝在其中添加警告。我显然错过了某些事情或在某处犯了一个小错误但我无法发现它。

3 个答案:

答案 0 :(得分:6)

哈!我脑子里一片空白。

我忘了将协议实现声明移动到类别的界面,如下所示:

#import "TopVC.h"

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:0)

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

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

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

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