Проблемы с циклическим импортом в Objective C и Cocoa Touch

#objective-c #cocoa-touch #import #circular-dependency

#objective-c #cocoa-touch #импорт #циклическая зависимость

Вопрос:

У меня есть контроллер представления в Cocoa Touch, который определяет, когда устройство вращается, и переключается между представлениями 2 контроллеров представления, которые у него есть: альбомная и портретная.

Я хочу UIViewControllers , чтобы в нем можно было получить доступ к FRRRotatingViewController , аналогично тому, как все UIViewControllers могут получить доступ UINavigationController к тому, в чем они находятся.

Итак, я создал UIViewController подкласс ( FRRViewController ), который будет иметь rotatingViewController свойство.

Я также изменил FRRRotatingViewController , поэтому он принимает FRRViewControllers вместо обычного UIViewControllers .

К сожалению, когда я включаю FRRRotatingViewController.h in FRRViewController.h (и наоборот), я, похоже, сталкиваюсь с проблемой циклического импорта. Я не знаю, как это исправить. Есть предложения?

Вот код:

 //
//  FRRViewController.h

#import <UIKit/UIKit.h>
#import "FRRRotatingViewController.h"

@interface FRRViewController : UIViewController

@end

//
//  FRRRotatingViewController.h

#import <UIKit/UIKit.h>
#import "FRRViewController.h"

@class FRRRotatingViewController;


@protocol FRRRotatingViewControllerDelegate

-(void) FRRRotatingViewControllerWillSwitchToLandscapeView: (FRRRotatingViewController *) sender;
-(void) FRRRotatingViewControllerWillSwitchToPortraitView: (FRRRotatingViewController *) sender;

@end


@interface FRRRotatingViewController : FRRViewController {
    // This is where I get the error:Cannot find interface declaration for
    // 'FRRViewController', superclass of 'FRRRotatingViewController'; did you 
    // mean 'UIViewController'?
}

@property (strong) UIViewController *landscapeViewController;
@property (strong) UIViewController *portraitViewController;

@property (unsafe_unretained) id<FRRRotatingViewControllerDelegate> delegate;

-(FRRRotatingViewController *) initWithLandscapeViewController: (UIViewController *) landscape andPortraitViewController: (UIViewController *) portrait;
-(void) deviceDidRotate: (NSNotification *) aNotification;

@end
  

Комментарии:

1. Чтобы импортировать A в B, добавьте @class A в B.h и #import «A.h» в B.m. То же самое для импорта B в A.

2. Почему бы не создать подкласс UIViewController с одной новой реализацией (например, FernardosViewController), содержащий любые методы, которые вы хотите использовать для подклассов? Тогда у вас были бы FRRRotatingViewController и FRRViewController, производные от FernardosViewController, и вы могли бы сохранять ссылки друг на друга (что избавило бы вас от проблемы с циклическим импортом) в файлах .h.

3. Добавление прямого объявления в FRRRotatingViewController в FRRViewController и импорт FRRViewController в FRRViewController.h решили эту проблему. Компилятор не принял бы суперкласс, который является прямым объявлением.

Ответ №1:

В большинстве ситуаций вы можете использовать прямые объявления для классов и протоколов в заголовках, чтобы избежать проблем с циклическим импортом, за исключением случаев наследования. Вместо FRRViewController.h импорта FRRRotatingViewController.h вы не можете сделать прямое объявление?

 @class FRRRotatingViewController;
  

Ответ №2:

Если я правильно понял, ваша структура наследования выглядит так:

UIViewController -> FRRViewController -> FRRRotatingViewController

Но вы сделали объявление FRRViewController зависимым от импорта файла из его подкласса FRRRotatingViewController. Поэтому компилятор будет импортировать и считывать FRRRotatingViewController перед обработкой остальной части FRRViewController.h.

Я предполагаю, что вы пропустили часть FRRViewController.h, поскольку там нет ссылки на какие-либо контроллеры вращающихся представлений, но если вы объявляете свойство в .h FRRRotatingViewController , тогда вам нужно использовать прямое объявление в FRRViewController.h:

 @class FRRRotatingViewController
  

вместо

 #import "FRRRotatingViewController.h"
  

Последнюю строку вы можете поместить в первую строку вашего FRRViewController.m файла.