2009-08-03 12 views
11

I mają następujące oznaczenia:Cel C pętli #import

#import <Foundation/Foundation.h> 
#import "ServerRequest.h" // works even though this line is included 
#import "ServerResponseRecord.h" 

@protocol ServerRequestDelegate<NSObject> 

-(void)request:(id)request gotResponseRecord:(ServerResponseRecord*)response; 
-(void)request:(id)request gotError:(NSError*)error; 

@end 

kompiluje i działa poprawnie. Jednakże, jeśli mogę wymienić deklaracji metody z:

-(void)request:(ServerRequest*)request gotResponseRecord:(ServerResponseRecord*)response; 
-(void)request:(ServerRequest*)request gotError:(NSError*)error; 

pojawia się nieoczekiwany błąd składni „Błąd: Oczekiwano«)»przed«ServerRequest»”. Jedynym powodem, dla którego mogę myśleć, że to może być problem, jest to, że ServerRequestDelegate.h i ServerRequest.h #importują się nawzajem. Nie rozumiem jednak, dlaczego kod działa z linią #import z żądaniem (id). Nie rozumiem również, dlaczego jest to błąd składniowy.

Czy ktoś może podać dobre wyjaśnienie?

+1

http://stackoverflow.com/questions/10019961/objective-c-class-directive-before-interface ma wyraźny przykład pętli importu i jak tego uniknąć za pomocą '@ class'. – bbum

Odpowiedz

24

Wspomniał pan już o wyjaśnieniu: cykl #importu.

Pierwszą rzeczą, którą mogę zrobić, to usunąć #include i dodaj następującą linię powyżej definicji @protocol:

@class ServerRequest; 

To naprzód deklaracja klasy, a może pomóc przełamać pętli importu. Aby uzyskać więcej informacji, sprawdź numer this SO question. Apple ma również krótkie wyjaśnienie w this guide.

Zasadniczo #import „ing plik powoduje kompilator przynieść cały tekst tego pliku do danego pliku, i choć #import jest«mądrzejszy»niż #include, to nie znaczy, że jesteś wolny od błędów importu . Deklaracja @class jest sposobem poinformowania kompilatora, że ​​klasa istnieje bez importowania nagłówka. Jest odpowiedni do użycia, gdy potrzebujesz tylko znać nazwę klasy, ale nie przejmuj się metodami, które zapewnia. Ogólnie rzecz biorąc, chcesz użyć pliku @class w pliku .h i #import w pliku .m, w którym faktycznie wchodzisz w interakcję z klasą.

+0

Tak, przejście do deklaracji @klasy w nagłówku jest lepsze na dowolnej liczbie poziomów, ale dopóki problem nie jest zależnością cykliczną bez odpowiedniej deklaracji forward, nadal może być ukryty błąd w nagłówku. –

+1

To prawda, ale fakt, że działa z nagłówkiem, jeśli używa "id" jako typu, ale nie, gdy statyczne wpisanie jako 'ServerRequest *' wskazuje, że nagłówek jest prawdopodobnie w porządku, a kompilator ma tylko problem, gdy zaczyna próbować uzyskać informacje o klasie "ServerRequest". –

0

#import "pętle" nie stanowią problemu. #import jest takie samo jak #include, z tym wyjątkiem, że śledzi pliki i zapewnia, że ​​preprocesor odczytuje je tylko za pierwszym razem.

Zwykle, gdy pojawi się taki błąd, jest to spowodowane problemem w załączonym pliku. Tak więc błąd prawdopodobnie występuje w ServerResponseRecord.h, prawdopodobnie jest potknięty przez faktyczne użycie zadeklarowanego przez niego obiektu. Nie widząc kompletnych nagłówków, nie można dokładnie powiedzieć, co się dzieje.

+0

Jeśli wystąpił problem w ServerResponseRecord, dlaczego mój kod byłby skompilowany i działał poprawnie, jeśli zmienię typ na id? – tba

+0

Ponieważ preprocesor jest sztuczką, a niektóre rozszerzenia mogą być uruchamiane tylko w niektórych przypadkach, ale nie w innych. Jeśli patrzysz na plik w izolacji, wydaje się, że dobrze, jeśli ServerRequest i ServerResponseRecord mają poprawne definicje. Poprzez przekazanie do przodu deklaracji używając @class udowodniłeś to, co oznacza, że ​​w jednym z twoich innych nagłówków występuje ukryty błąd, który tylko w niektórych przypadkach wyzwala. –