3

複数のプロトコルを実装する必要があるビュー コントローラー クラスがあります。整理整頓しすぎないように、各プロトコルのメソッドをビュー コントローラー クラスのカテゴリに入れる習慣があります。

今回は、クラスがいずれかのプロトコルを実装していないという警告をリンカから受け取りました。メソッドは実行時に機能しますが、リンカーはカテゴリ内の実装を認識できないようです。

別のプロジェクトでクラスを単純化したところ、同じ場所で同じエラーが発生しました。

クラスヘッダー:

#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すべて必須であることです。

それでも、リンカーが文句を言ったとしても、メソッドは実行時に呼び出されます。警告のあるビルドを拒否するだけです。どうやら何かを見逃したか、どこかで些細な間違いを犯したようですが、それを見つけることはできません。

4

3 に答える 3

6

ハッ!私は脳が空白になっていました。

次のように、プロトコルの実装宣言をカテゴリのインターフェイスに移動するのを忘れていました。

#import "TopVC.h"

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

これは警告なしでコンパイルされ、期待どおりに動作します。

メソッドの実装が見つからない場合、リンカーが無視するオプションのプロトコルを非常に多く使用すると、私は怠け者になりました。

于 2010-03-06T02:02:24.837 に答える
2

プロトコルを宣言することにより、プライマリ インターフェイスで実装することを意図し、コンパイラはプライマリ実装でメソッドを確認することを期待します (「... [それ] は、変更のない自動生成されたものです」と述べています)。コンパイラは、カテゴリ内のメソッドを実装しようとしていることを知りません。それが知っているのは、あなたは彼らがそこにいると「約束した」が、彼らが期待していた場所にそれらを提供できなかったということだけです。

于 2010-03-06T00:34:07.393 に答える
0

コンパイラがTopVC.mをコンパイルしているとき、他のファイルが残りの必要なプロトコルメソッドを提供することを知る方法はありません。gccでは、すべての.mファイルが個別にコンパイルされます。このようなものを別々のカテゴリに分割したいというあなたの願望は問題ありませんが、それらすべてをTopVC.mに実装する必要があります。

のプロトコルメソッドを再定義しTopVC+ABPeoplePickerNavigationControllerDelegate.hても、何の影響もありません。@interfaceの特定のカテゴリタグと@implementationの特定のカテゴリタグの間に関係はありません。@interfaceのカテゴリ定義は、「コンパイラの警告を生成せずにこのオブジェクトに渡すことが合法である他のメソッドがいくつかあります」とだけ言っています。そのようなメソッドを作成することは、明示的な約束でさえありません。これは、プロトコルに準拠していることを示したときにすでに処理されています(これはメソッドの実装を約束するものです)。

@implementationのカテゴリ定義は、「このクラスの他のメソッドがいくつかあります」とだけ言っています。カテゴリタグ自体はコメントにすぎません。それは決して相関していません。

プロトコルの実装をTopVC.mに移動する必要があり、TopVC+<protocol>.hファイルを用意する理由はありません。.mを個別の@implementationブロックに分割したい場合は、それで問題ありません。そのようにする人を知っています。個人的には#pragma mark、ファイルを分割するために使用します。

于 2010-03-06T00:47:53.943 に答える