【问题标题】:Protocol Methods not Recognized When Implemented in a Category在类别中实现时无法识别的协议方法
【发布时间】:2010-03-06 00:16:23
【问题描述】:

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

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

我在另一个项目中简化了课程,但在同一个地方出现了同样的错误。

类头:

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

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

【问题讨论】:

    标签: iphone objective-c protocols xcodebuild categories


    【解决方案1】:

    哈!我当时脑子一片空白。

    我忘记将协议实现声明移动到类别的接口,如下所示:

    #import "TopVC.h"
    
    @interface TopVC (ABPeoplePickerNavigationControllerDelegateMethods) <ABPeoplePickerNavigationControllerDelegate>
    ...
    @end
    

    这会在没有警告的情况下编译并按预期工作。

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

    【讨论】:

    • 你好,我做的一切都像你一样,我得到了错误:Category is implementing a method which will also be in its primary class。我做错了什么或者只是这种方式不再相关?
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-03
        • 1970-01-01
        • 1970-01-01
        • 2022-10-04
        • 2011-12-16
        • 1970-01-01
        相关资源
        最近更新 更多