@ class vs. # import

Z tego, co wiem, należy użyć deklaracji forward-class w przypadku, gdy ClassA musi zawierać nagłówek Classa, A CLASSA musi zawierać nagłówek ClassA, aby uniknąć okrągłych inkluzji. Rozumiem również, że An #import jest prostym ifndef tak, że include zdarza się tylko raz.

Moje pytanie brzmi: kiedy używa się #import, a kiedy używa się @class? Czasami, jeśli używam deklaracji @class, widzę wspólne Ostrzeżenie kompilatora, takie jak po:

warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.

Naprawdę chciałbym to zrozumieć, zamiast usuwać @class forward-declaration i rzucać #import w celu wyciszenia ostrzeżeń, które daje mi kompilator.

Author: notedible, 2008-11-27

16 answers

Jeśli widzisz to Ostrzeżenie:

Warning: receiver 'MyCoolClass' jest klasą forward I odpowiedni interfejs @może nie istnieć

Musisz #import plik, ale możesz to zrobić w swoim pliku implementacji (.m) i użyj deklaracji @class w pliku nagłówkowym.

@class nie usuwa (zazwyczaj) potrzeby plików #import, po prostu przesuwa wymóg w dół bliżej miejsca, w którym informacje są użyteczne.

Na Przykład

Jeśli powiesz @class MyCoolClass, kompilator wie, że może zobaczyć coś w stylu:

MyCoolClass *myObject;

Nie musi się martwić o coś innego niż MyCoolClass jest poprawną klasą i powinna zarezerwować miejsce na wskaźnik do niej(tak naprawdę, tylko wskaźnik). Tak więc w nagłówku @class wystarcza 90% czasu.

Jednakże, jeśli kiedykolwiek będziesz potrzebował utworzyć lub uzyskać dostęp do członków myObject, musisz powiadomić kompilator, czym są te metody. W tym momencie (prawdopodobnie w Twoim plik implementacji), musisz #import "MyCoolClass.h", aby przekazać kompilatorowi dodatkowe informacje poza "this is A class".

 756
Author: Ben Gottlieb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-28 04:59:03

Trzy proste zasady:

  • tylko #import Super klasa i przyjÄ™te protokoÅ‚y, w plikach nagłówkowych (.h Pliki).
  • #import wszystkie klasy i protokoÅ‚y, do których wysyÅ‚ane sÄ… wiadomoÅ›ci w implementacji (.m pliki).
  • deklaracje Forward dla wszystkiego innego.

Jeśli robisz deklarację forward w plikach implementacji, to prawdopodobnie robisz coś złego.

 182
Author: PeyloW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 10:50:19

Spójrz na dokumentację języka programowania Objective-C na ADC

Pod sekcjÄ… o definiowaniu interfejsu klasy / klasy opisuje dlaczego tak siÄ™ dzieje:

Dyrektywa @ class minimalizuje ilość kodu widzianego przez kompilator i linker, dlatego jest najprostszym sposobem na przekazanie deklaracji forward nazwy klasy. Jest prosty, pozwala uniknąć potencjalnych problemów, które mogą pochodzić z importowania plików, które importują jeszcze inne pliki. Na przykład, jeśli jedna klasa deklaruje statycznie wpisaną zmienną instancji innej klasy, a ich dwa pliki interfejsu importują się nawzajem, żadna z klas nie może się poprawnie skompilować.

Mam nadzieję, że to pomoże.

 110
Author: Abizern,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 18:21:52

W razie potrzeby użyj deklaracji forward w pliku nagłówkowym oraz #import plików nagłówkowych dla klas, których używasz w implementacji. Innymi słowy, zawsze #import pliki, których używasz w swojej implementacji, a jeśli chcesz odwołać się do klasy w pliku nagłówkowym, użyj również deklaracji forward.

Wyjątek do tego jest taki, że powinieneś #import klasy lub formalnego protokołu, z którego dziedziczysz w pliku nagłówkowym (w takim przypadku nie musisz go importować w realizacji).

 48
Author: Marc Charbonneau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-09 12:30:49

Powszechną praktyką jest używanie @ class w plikach nagłówkowych (ale nadal musisz # zaimportować superklasę) i # import w plikach implementacyjnych. Pozwoli to uniknąć okrągłych inkluzji i po prostu działa.

 24
Author: Steph Thirion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 01:04:51

Kolejna zaleta: szybka kompilacja

Jeśli dołączysz plik nagłówkowy, każda zmiana w nim spowoduje kompilację bieżącego pliku, ale nie dzieje się tak, jeśli nazwa klasy jest dołączona jako @class name. Oczywiście musisz dołączyć nagłówek do pliku źródłowego

 24
Author: vent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-14 18:58:53
Moje zapytanie jest takie. Kiedy używa się # import, a kiedy @ class?

Prosta odpowiedź: Ty #import LUB #include gdy istnieje fizyczna zależność. W przeciwnym razie korzystasz z deklaracji forward (@class MONClass, struct MONStruct, @protocol MONProtocol).

Oto kilka typowych przykładów uzależnienia fizycznego:

  • dowolna wartość C lub C++ (wskaźnik lub odniesienie nie jest fizycznÄ… zależnoÅ›ciÄ…). JeÅ›li masz CGPoint jako wÅ‚asność ivar lub, kompilator bÄ™dzie musiaÅ‚ zobaczyć deklaracjÄ™ z dnia CGPoint.
  • twoja superklasa.
  • metoda, której używasz.

Czasami, gdy używam deklaracji @ class, widzę wspólne Ostrzeżenie kompilatora, takie jak następujące: "Ostrzeżenie: odbiornik 'FooController' jest klasą forward I odpowiedni interfejs @może nie istnieć."

Kompilator jest pod tym względem bardzo pobłażliwy. Spowoduje to upuszczenie podpowiedzi (takich jak ta powyżej), ale możesz łatwo zniszczyć swój stos, jeśli je zignorujesz i nie #import poprawnie. Chociaż powinno (IMO), kompilator tego nie wymusza. W ARC kompilator jest bardziej rygorystyczny, ponieważ odpowiada za zliczanie referencji. To, co się dzieje, to kompilator wraca do wartości domyślnej, gdy napotka nieznaną metodę, którą wywołujesz. Każda zwracana wartość i parametr jest przyjmowana jako id. Dlatego powinieneś wyeliminować każde Ostrzeżenie ze swoich baz kodowych, ponieważ powinno to być uważane za uzależnienie fizyczne. Jest to analogiczne do wywołania funkcji C, która nie jest zadeklarowana. Z C, parametry przyjmuje się za int.

Powodem, dla którego preferujesz deklaracje forward, jest to, że możesz skrócić czas budowania o czynniki, ponieważ istnieje minimalna zależność. W przypadku deklaracji forward kompilator widzi, że istnieje nazwa i może poprawnie parsować i kompilować program bez oglądania deklaracji klasy lub wszystkich jej zależności, gdy nie ma fizycznej zależności. Czyszczenie konstrukcji zajmuje mniej czasu. Przyrostowe Kompilacje zajmują mniej czasu. Pewnie, że w końcu wydasz trochę więcej czasu upewniając się, że wszystkie nagłówki, których potrzebujesz, są widoczne dla każdego tłumaczenia, ale opłaca się to w krótkim czasie budowania (zakładając, że twój projekt nie jest mały).

Jeśli zamiast tego użyjesz #import LUB #include, wrzucasz dużo więcej pracy do kompilatora, niż jest to konieczne. Wprowadzasz również złożone zależności nagłówka. Można to porównać do algorytmu brute-force. Kiedy #import, przeciągasz Tony niepotrzebnych informacji, które wymagają wiele pamięci, We/Wy dysku i procesora do analizy i kompilacji źródeł.

ObjC jest dość blisko ideału dla języka C w odniesieniu do Zależności, ponieważ NSObject typy nigdy nie są wartościami -- NSObject typy są zawsze liczonymi wskaźnikami odniesienia. Tak więc możesz ujść na sucho z niewiarygodnie szybkim czasem kompilacji, jeśli odpowiednio ustrukturyzujesz zależności programu i prześlij je tam, gdzie to możliwe, ponieważ wymagana jest bardzo mała zależność fizyczna. Możesz również zadeklarować właściwości w klasie rozszerzenia, aby jeszcze bardziej zminimalizować zależność. To ogromny bonus dla dużych systemów-wiedziałbyś, jaka to różnica, gdybyś kiedykolwiek opracował dużą bazę kodu C++.

Dlatego moim zaleceniem jest, aby używać do przodu, gdzie to możliwe, a następnie #import tam, gdzie istnieje zależność fizyczna. Jeśli widzisz ostrzeżenie lub inne, które implikuje fizyczne uzależnienie-napraw je wszystkie. Poprawką jest #import w pliku implementacji.

Podczas budowania bibliotek, prawdopodobnie klasyfikujesz niektóre interfejsy jako grupa, w którym to przypadku należy #import tę bibliotekę, w której wprowadzono zależność fizyczną (np. #import <AppKit/AppKit.h>). Może to wprowadzić zależność, ale opiekunowie bibliotek często mogą obsłużyć fizyczne zależności dla Ciebie w razie potrzeby - jeśli wprowadzą jakąś funkcję, mogą zminimalizować wpływ, jaki ma ona na twoje Kompilacje.

 18
Author: justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-12 23:02:30

Widzę wiele "zrób to w ten sposób", ale nie widzę żadnych odpowiedzi na "Dlaczego?"

Więc: Dlaczego należy @class w nagłówku a #import tylko w implementacji? Podwajasz swoją pracę przez konieczność @class i # import przez cały czas. Chyba, że skorzystasz z dziedziczenia. W takim przypadku będziesz # importować wiele razy dla jednej klasy@. Następnie musisz pamiętać, aby usunąć z wielu różnych plików, jeśli nagle uznasz, że nie potrzebujesz dostępu do deklaracji już nie.

Wielokrotne Importowanie tego samego pliku nie jest problemem ze względu na charakter # import. Kompilowanie wydajności też nie jest problemem. Gdyby tak było, nie bylibyśmy # importowanie Kakao/Kakao.h lub tym podobne w prawie każdym pliku nagłówkowym, który mamy.

 11
Author: Bruce Goodwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 15:51:46

Jeśli to zrobimy

@interface Class_B : Class_A

Oznacza, że dziedziczymy Class_A do Class_B, w Class_B możemy uzyskać dostęp do wszystkich zmiennych class_A.

Jeśli to robimy

#import ....
@class Class_A
@interface Class_B

Tutaj mówimy, że używamy Class_A w naszym programie, ale jeśli chcemy użyć zmiennych Class_A w Class_B musimy # import Class_A w .plik m (Utwórz obiekt i użyj jego funkcji i zmiennych).

 7
Author: Anshuman Mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-04 06:32:03

Aby uzyskać dodatkowe informacje o zależnościach plików & # import & @ class Sprawdź to:

Http://qualitycoding.org/file-dependencies / Itis dobry artykuł

Streszczenie artykułu

IMPORT w plikach nagłówkowych:

  • #Importuj klasÄ™ nadrzÄ™dnÄ…, którÄ… dziedziczysz, oraz protokoÅ‚y, które implementujesz.
  • Forward-deklaruje Wszystko inne (chyba że pochodzi z frameworka z nagłówkiem głównym).
  • spróbuj wyeliminować wszystkie inne # imports.
  • deklarujÄ… protokoÅ‚y we wÅ‚asnych nagłówkach, aby zmniejszyć zależnoÅ›ci.
  • zbyt wiele deklaracji forward? Masz dużą klasÄ™.

IMPORT w plikach wykonawczych:

  • wyeliminuj cruft #import, który nie jest używany.
  • jeÅ›li metoda deleguje do innego obiektu i zwraca to, co otrzymuje back, try to forward-declare that object zamiast # importing it.
  • JeÅ›li wÅ‚Ä…czenie moduÅ‚u zmusza do wÅ‚Ä…czenia poziomu po poziom kolejne zależnoÅ›ci, możesz mieć zestaw klas, które chcÄ… zostaÅ„ bibliotekÄ…. Zbuduj jÄ… jako oddzielnÄ… bibliotekÄ™ z mistrzem nagłówek, dziÄ™ki czemu wszystko może być wniesione jako pojedynczy wstÄ™pnie zbudowany kawaÅ‚ek.
  • za dużo # import? Masz dużą klasÄ™.
 5
Author: Homam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 11:16:58

Kiedy się rozwijam, mam na myśli tylko trzy rzeczy, które nigdy nie sprawiają mi żadnych problemów.

  1. Import Super klas
  2. Importuj klasy rodzica (gdy masz dzieci i rodziców)
  3. Import klas poza projektem (np. w frameworkach i bibliotekach)

Dla wszystkich innych klas (podklas i klas potomnych w moim projekcie), deklarujÄ™ je poprzez forward-class.

 3
Author: Constantino Tsarouhas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-18 15:42:16

Jeśli spróbujesz zadeklarować zmienną lub właściwość w pliku nagłówkowym, której jeszcze nie zaimportowałeś, pojawi się błąd mówiący, że kompilator nie zna tej klasy.

Twoja pierwsza myśl to prawdopodobnie #import to.
W niektórych przypadkach może to powodować problemy.

Na przykład, jeśli zaimplementujesz kilka C-metod w pliku nagłówkowym, strukturach lub czymś podobnym, ponieważ nie powinny być importowane wiele razy.

Dlatego można powiedzieć kompilator z @class:

Wiem, że nie znasz tej klasy, ale ona istnieje. To będzie zaimportowane lub zaimplementowane gdzie indziej

W zasadzie mówi kompilatorowi, aby się zamknął i skompilował, nawet jeśli nie jest pewien, czy ta klasa zostanie kiedykolwiek zaimplementowana.

Zazwyczaj używasz #import w .m i @class w .h pliki.

 3
Author: IluTov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-07 12:18:18

Deklaracja Forward tylko do kompilatora prevent przed wyświetlaniem błędu.

Kompilator będzie wiedział, że istnieje klasa o nazwie, której użyłeś w swoim pliku nagłówkowym do zadeklarowania.

 0
Author: karthick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-26 08:36:46

Kompilator będzie narzekał tylko wtedy, gdy zamierzasz używać tej klasy w taki sposób, że kompilator musi znać swoją implementację.

Ex:

  1. to może być tak, jeśli zamierzasz czerpać z tego swoją klasę lub
  2. Jeśli chcesz mieć obiekt tej klasy jako zmienną członkowską (choć rzadką).

Nie będzie narzekać, jeśli masz zamiar użyć go jako wskaźnika. Oczywiście trzeba będzie # zaimportować go do pliku implementacji (jeśli tworzenie instancji obiektu tej klasy), ponieważ musi znać zawartość klasy, aby utworzyć instancję obiektu.

Uwaga: # import nie jest taki sam jak # include. Oznacza to, że nie ma nic zwanego importem kołowym. import jest rodzajem żądania, aby kompilator spojrzał na konkretny plik w celu uzyskania pewnych informacji. Jeśli te informacje są już dostępne, kompilator je ignoruje.

Po prostu spróbuj, Importuj A. h W B. H I B. h W A. h. nie będzie żadnych problemów ani skarg i będzie działać dobrze też.

Kiedy używać @ class

Używasz @ class tylko wtedy, gdy nie chcesz importować nagłówka do nagłówka. To może być przypadek, w którym nawet nie zależy ci na tym, jakie będą zajęcia. Przypadki, w których możesz nie mieć jeszcze nagłówka dla tej klasy.

Przykładem może być to, że piszesz dwie biblioteki. Jedna klasa, nazwijmy ją A, istnieje w jednej bibliotece. Ta biblioteka zawiera nagłówek z drugiej biblioteki. Ten nagłówek może mieć wskaźnik ale znowu może nie trzeba go używać. Jeśli Biblioteka 1 nie jest jeszcze dostępna, biblioteka B nie zostanie zablokowana, jeśli użyjesz @ class. Ale jeśli chcesz zaimportować A. h, postęp biblioteki 2 jest zablokowany.

 0
Author: Deepak G M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-18 11:15:21

Myśl o @ class jako o mówieniu kompilatorowi "zaufaj mi, to istnieje".

Pomyśl o # import jako kopiuj-wklej.

Chcesz zminimalizować liczbę importów, które masz z wielu powodów. Bez żadnych badań pierwszą rzeczą, która przychodzi na myśl, jest to, że skraca czas kompilacji.

Zauważ, że kiedy dziedziczysz po klasie, nie możesz po prostu użyć deklaracji forward. Musisz zaimportować plik, aby deklarowana Klasa wiedziała, jak jest zdefiniowana.

 0
Author: Brandon M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-04 16:10:38

Jest to przykładowy scenariusz, w którym potrzebujemy @ class.

Rozważ, że jeśli chcesz utworzyć protokół w pliku nagłówkowym, który ma parametr o typie danych tej samej klasy, możesz użyć @ class. Pamiętaj, że możesz również deklarować protokoły osobno, to tylko przykład.

// DroneSearchField.h

#import <UIKit/UIKit.h>
@class DroneSearchField;
@protocol DroneSearchFieldDelegate<UITextFieldDelegate>
@optional
- (void)DroneTextFieldButtonClicked:(DroneSearchField *)textField;
@end
@interface DroneSearchField : UITextField
@end
 0
Author: Sujananth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 14:44:06