Методы протокола, не распознаваемые при реализации в категории - PullRequest
3 голосов
/ 06 марта 2010

У меня есть класс контроллера представления, который должен реализовать несколько протоколов. Слишком аккуратно. У меня есть привычка помещать методы каждого протокола в категорию в классе контроллера представления.

На этот раз я получаю предупреждения от компоновщика, что класс не реализует один из протоколов. Методы работают во время выполнения, компоновщик просто не может распознать реализацию в категории.

Я упростил класс в другом проекте и получаю ту же ошибку в том же месте.

Заголовок класса:

#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 ]

6 голосов
/ 06 марта 2010

Хах! У меня был пустой мозг.

Я забыл переместить объявление реализации протокола в интерфейс категории следующим образом:

#import "TopVC.h"

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

Это компилируется без предупреждения и работает как положено.

Мне просто стало лень, когда я использую так много дополнительных протоколов, которые компоновщик игнорирует, если не может найти реализации метода.

2 голосов
/ 06 марта 2010

Объявляя протоколы, вы намерены реализовать на первичном интерфейсе компилятор ожидает увидеть методы в первичной реализации (о которых вы заявляете: «... [это] автоматически сгенерированный без изменений») ). Компилятор не знает, что вы собираетесь реализовать методы в категории. Все, что он знает: вы «пообещали», что они будут там, но вы не предоставили их там, где они ожидали.

0 голосов
/ 06 марта 2010

Когда компилятор компилирует TopVC.m, он не может знать, что какой-то другой файл предоставит остальные необходимые методы протокола. В gcc каждый файл .m компилируется независимо. Ваше желание разделить эти вещи на отдельные категории прекрасно, но все они должны быть реализованы в TopVC.m.

Ваше переопределение методов протокола в TopVC+ABPeoplePickerNavigationControllerDelegate.h ни на что не влияет. Нет никакой связи между определенным тегом категории в @interface и тегом @implementation. Определение категории в @interface просто говорит: «Вот некоторые другие методы, которые допустимо передавать этому объекту без генерации предупреждения компилятора». Это даже не явное обещание создавать такие методы. Это уже было обработано, когда вы указали, что вы соответствуете протоколу (который обещает реализовать методы).

Определение категории в @implementation просто говорит: «Вот некоторые другие методы для этого класса». Сам тег категории - не более чем комментарий. Это никак не связано.

Вам необходимо переместить реализации протокола в TopVC.m, и нет причины иметь файл TopVC+<protocol>.h. Если вам нравится разбивать ваш .m на отдельные блоки @implementation, это нормально, и я знаю людей, которые так поступают. Лично я просто использую #pragma mark, чтобы разбить файл.

...