#import не защищает от циклических звонков? - PullRequest
2 голосов
/ 29 сентября 2011

У меня есть два класса ClassA и Class B (они являются viewControllers).
Класс A является делегатом класса B.
ClassA "laucnhes" и экземпляр ClassB.
Методы вызова ClassB для classA.

Допустим, это:

#import "ClassB.h"

@interface ClassA : NSObject {
    ClassB* subController;
}

- (void) doThis;

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

#import "ClassA.h"

@interface ClassB : NSObject {
    ClassA* delegate;
}

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

@implementation ClassB

- (void) someMethod {
   AnObject* myObj = [self.delegate.arr objectAtIndex:8];
   [self.delegate doThis];
}

При этом A должен импортировать B, а B должен импортировать A.

Если B не импортирует A (только с @classA), есть ошибка компиляции для используемого атрибута из A.
Если B импортирует A, есть ошибка компиляции в строке ClassA* delegate.

Почему у меня есть эти ошибки компиляции?Разве #import не защищает снова рекурсивные вызовы?

Мне не нужно решение этой проблемы, я знаю, как я могу это сделать.
Но мне интересно, почему мой#import вызывают эти проблемы.Это не #include ...

Ответы [ 4 ]

6 голосов
/ 29 сентября 2011

В файлах .h предпочтение от @class от #import. Затем оба файла можно импортировать в файлы реализации .m.

// ClassA.h -------------------------------
@class ClassB;
@interface ClassA : NSObject {
    ClassB* subController;
}

- (void) doThis;

// ClassB.h -------------------------------
@class ClassA;
@interface ClassB : NSObject {
    ClassA* delegate;
}

// ClassB.m -------------------------------
#import "ClassA.h"
#import "ClassB.h"

@implementation ClassB

- (void) someMethod {
   AnObject* myObj = [self.delegate.arr objectAtIndex:8];
   [self.delegate doThis];
}

Использование операторов @class вместо #import также уменьшает зависимости и делает остальные более понятными. Это также может ускорить время компиляции.

5 голосов
/ 30 сентября 2011

Почему у меня эти ошибки компиляции? Разве #import не защищает снова рекурсивные вызовы?

#import защищает от неоднократного импорта одного и того же заголовка в один и тот же модуль, независимо от того, включает ли он / импортирует циклически или нет. Он защищает от этого, не позволяя вам сделать это: работает только первый #import заголовка; последующие #import s того же заголовка игнорируются.

В циклической ситуации #include препроцессор будет обходить круг несколько раз, а затем не сможет выполнить сборку, прежде чем вы доберетесь до компиляции. Использование #import предотвращает заклинивание препроцессора и позволяет преуспевать в успехе, но циклический код #import в лучшем случае все еще хитрый и обычно не компилируется.

Итак, перейдем к вашей конкретной ситуации.

Для кода, который вы указали в своем вопросе, @class будет работать с одним или обоими заголовками, и вы действительно должны использовать его в обоих. Вам также понадобится #import оба заголовка в обоих файлах .m.

Если B не импортирует A (только с @class A), существует ошибка компиляции для используемого атрибута из A.

Если вы имеете в виду «есть ошибка компиляции в каждой точке, где я использую этот атрибут типа ClassA *», тогда да: вы не можете общаться с этим объектом, потому что вы не импортировали его интерфейс, поэтому компилятор не знает, какие сообщения вы можете отправить ClassA экземпляру. Вот почему вам нужно импортировать его интерфейс.

Если B импортирует A, возникает ошибка компиляции на делегатской линии ClassA *.

Если оба заголовка импортируют друг друга, то у вас есть это:

ClassA.m:
    ClassA.h
        ClassB.h
            ClassA.h (ignored because this was already imported by ClassA.m)
ClassB.m:
    ClassB.h
        ClassA.h
            ClassB.h (ignored because this was already imported by ClassB.m)

Нет способа, которым это могло бы работать без одного интерфейса, предшествующего другому, без другого интерфейса, предшествующего ему. Это круг, с которым вы сталкиваетесь - круг, который #import существует, чтобы разорваться. #include разрешает круг и тем самым заклинивает:

ClassA.m:
    ClassA.h
        ClassB.h
            ClassA.h
                ClassB.h
                    ClassA.h
                        ClassB.h
                            ClassA.h
                                ClassB.h
                                    ClassA.h
                                        ClassB.h
                                            ClassA.h
                                                ClassB.h
                                                    (fails at some point)

Следовательно #import.

Таким образом, вы не можете импортировать каждый заголовок из другого. Отсюда @class.

Но вам все равно нужно импортировать каждый заголовок из каждого модуля. Это именно то, что вам нужно сделать: используйте @class в каждом заголовке и #import (на обоих заголовках) в каждом модуле.

1 голос
/ 29 сентября 2011

Этой жалобы компиляции можно избежать, объявив

@class ClassB;

в файле .h.ClassB.h затем может быть включен в файл .m.

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

См. этот (дубликат?) Вопрос для вашей философской проблемы.

0 голосов
/ 30 сентября 2011

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

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

...