Подтвердить что ты не робот

Не удается найти объявление протокола

У меня есть два 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
4b9b3361

Ответ 1

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

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 попытаются их использовать.

Ответ 2

Введите код объявления протокола над строками #import например.

@protocol -----

@end

import ----

@interface classname ---

Ответ 3

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

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

Ответ 4

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

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

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

@interface YourClassName () <YourProtocolName>
@end

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

Ответ 5

Попробуйте положить <BaseViewControllerDelegate> или <BigViewControllerDelegate> в файле реализации, а не в файле заголовка. Это будет работать.

Ответ 6

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

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

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