Не удается найти объявление протокола - PullRequest
59 голосов
/ 23 июня 2011

У меня есть два view controllers A и B, и они оба имеют друг друга в качестве своих делегатов.

Когда я ничего не делал, кроме определения протоколов в начале заголовочных файлов и #import файла заголовка другого, я получил две ошибки в виде -

не может найти объявление протокола для "BDelegate", который показывался в A.h (где я написал) не может найти объявление протокола для «ADelegate», который показывался в B.h (где я писал)

Просматривая онлайн, люди ранее писали, что циклическое включение заголовочных файлов может привести к проблемам. Они рекомендовали либо использовать #include, либо @class объявление вроде -

@class A

вместо

#import A.h

внутри #import B.h

Я перепробовал почти все комбинации этих импортов, @classes и #include, но все еще не могу избавиться от предупреждений. Кроме того, решения онлайн рекомендовали перенести #import в .m файлы, но это тоже не помогло. Частично причина в том, что онлайн-решения немного нечетки - если бы вы могли их сломать, это было бы здорово.

Любые предложения о том, что можно сделать, чтобы это исправить?


- BigViewController.h -

#import "BaseViewController.h"
#include "BaseViewController.h"

@class BigViewController;

@protocol BigViewControllerDelegate
-(void) BigViewController:(BigViewController *) bigView;
@end

@interface BigViewController : UIViewController <BaseViewControllerDelegate>
{    
     //delegate
     id <BigViewControllerDelegate> delegate;

ivars...    
}

@properties...
@end

--------------------------------------------------

- BaseViewController.h -

#<UIKit/UIKit.h>

#import "BigViewController.h"
#include "BigViewController.h"

@class BigViewController;

@protocol BaseViewControllerDelegate
- (void) setParametersWithItemChosen:(Item *) item;
@end

@interface BaseViewController : UIViewController <...BigViewControllerDelegate...>
{

   ivars...

   //delegate
    id <BaseViewControllerDelegate> delegate;
}

@properties...
@end

Ответы [ 6 ]

101 голосов
/ 23 июня 2011

Позвольте мне уменьшить выборку еще больше и обозначить строки:

VC1.h

#import "VC2.h"  // A

@class VC1;

@protocol VC1Delegate // B
@end

@interface VC1 : UIViewController <VC2Delegate> // C
@end

VC2.h

#import "VC1.h"  // D

@class VC2;

@protocol VC2Delegate // E
@end

@interface VC2 : UIViewController <VC1Delegate> // F
@end

Рассмотрим, что происходит, когда что-то #imports VC1.h: достигает строки A, затем выполняется импорт.Строка D ничего не делает, потому что VC1.h уже был импортирован.Затем строка E обрабатывается.Затем строка F, и мы получаем ошибку, потому что мы еще не дошли до строки B, поэтому протокол не объявлен!

Рассмотрим, что происходит, когда что-то #imports VC2.h: Достигает строки D, затемимпорт обработан.Строка A ничего не делает, потому что VC2.h уже был импортирован.Затем строка B обрабатывается.Затем строка C, и мы получаем ошибку, потому что мы еще не дошли до строки E, поэтому протокол не объявлен!

Первым шагом является пересмотр того, действительно ли оба этих класса должны быть делегатами друг друга.,Если вы можете разорвать цикл, это, вероятно, будет путь.Если нет, вам нужно реструктурировать заголовки.Наиболее простой способ - это, вероятно, поместить делегатов в собственные заголовки:

VC1Delegate.h

@class VC1;

@protocol VC1Delegate // B
@end

VC1.h

#import "VC1Delegate.h"
#import "VC2Delegate.h"

@interface VC1 : UIViewController <VC2Delegate> // C
@end

VC2Delegate.h

@class VC2;

@protocol VC2Delegate // E
@end

VC2.h

#import "VC1Delegate.h"
#import "VC2Delegate.h"

@interface VC2 : UIViewController <VC1Delegate> // F
@end

Если вы отслеживаете импорт сейчасвы увидите, что соответствующие протоколы теперь будут всегда объявляться до того, как строки @interface попытаются их использовать.

100 голосов
/ 22 января 2013

Записать код объявления протокола над строками #import, например,

@ protocol -----

@ end

import ----

@ имя класса интерфейса ---

37 голосов
/ 11 апреля 2012

У меня была почти такая же проблема, и я исправил ее благодаря ответу выше, но немного другим способом.

Все, что я сделал, это поставил строку #import после объявление протокола в заголовочном файле.надеюсь, я смогу помочьи если кто-то знает, что это плохое программирование по какой-то причине, пожалуйста, дайте мне знать

10 голосов
/ 18 ноября 2014

Я нашел другое решение этой проблемы, потому что мне не очень понравилась идея просто вставить #imports между классом и объявлением протокола.

Обычно вы просто перемещаете <YourProtocolName> из файла класса .h в расширение класса в файле .m

Итак, в вашем .m файле вы добавляете

@interface YourClassName () <YourProtocolName>
@end

Я не знаю, действительно ли это хорошая практика, но похоже, что это более чистое решение, позволяющее избежать циклов импорта.

8 голосов
/ 06 января 2016

Попробуйте поместить или в файл реализации, а не в файл заголовка. Это будет работать.

3 голосов
/ 04 марта 2013

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

Но потом я подумал, а зачем вообще импортировать делегата? Я не ссылался на его свойства и не вызывал ни один из его методов напрямую (для этого и был объявлен протокол).

Я попытался закомментировать импорт делегата и увидел, где возникла ошибка, и обнаружил, что то, что я импортировал при импорте делегата, на самом деле было декларацией, которую импортировал делегат, т.е. я импортировал A (также мой делегат ), A импортировал B, то, что я фактически использовал, было B. Поэтому я оставил импорт A закомментированным и добавил импорт для B. Затем я мог вернуть порядок протокола импорта обратно, как это было.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...