Moje zapytanie jest takie. Kiedy używa się #import, a kiedy używa @class?
Prosta odpowiedź: Ty #import
lub #include
kiedy istnieje fizyczna zależność. W przeciwnym razie, należy użyć do przodu deklaracji ( @class MONClass
, struct MONStruct
, @protocol MONProtocol
).
Oto kilka typowych przykładów fizycznej zależności:
- Dowolna wartość C lub C ++ (wskaźnik lub odwołanie nie jest zależnością fizyczną). Jeśli masz
CGPoint
jako ivar lub właściwość, kompilator będzie musiał zobaczyć deklarację CGPoint
.
- Twoja nadklasa.
- Metoda, której używasz.
Czasami, jeśli używam deklaracji @class, widzę wspólne ostrzeżenie kompilatora, takie jak: „ostrzeżenie: odbiornik„ FooController ”jest klasą przekazującą i odpowiedni @ interfejs może nie istnieć.”
Kompilator jest pod tym względem bardzo łagodny. Będzie upuszczał podpowiedzi (takie jak powyższe), ale możesz łatwo wyrzucić stos, jeśli je zignorujesz i nie zrobisz tego #import
poprawnie. Chociaż powinien (IMO), kompilator tego nie wymusza. W ARC kompilator jest bardziej rygorystyczny, ponieważ odpowiada za zliczanie referencji. Dzieje się tak, gdy kompilator wraca do stanu domyślnego, gdy napotyka nieznaną metodę, którą wywołujesz. Przyjmowana jest każda zwracana wartość i parametr id
. Dlatego należy usunąć każde ostrzeżenie z baz kodu, ponieważ należy to uznać za zależność fizyczną. Jest to analogiczne do wywoływania funkcji C, która nie jest zadeklarowana. W przypadku C zakłada się, że parametry są int
.
Powodem, dla którego preferujesz deklaracje forward, jest to, że możesz skrócić czas kompilacji przez czynniki, ponieważ istnieje minimalna zależność. W przypadku deklaracji przesyłania dalej kompilator widzi nazwę i może poprawnie parsować i kompilować program bez wyświetlania deklaracji klasy lub wszystkich jej zależności, gdy nie ma zależności fizycznej. Czyste wersje zajmują mniej czasu. Kompilacje przyrostowe zajmują mniej czasu. Oczywiście skończysz trochę dłużej, upewniając się, że wszystkie potrzebne nagłówki są widoczne w każdym tłumaczeniu, ale szybko się to zwraca (przy założeniu, że twój projekt nie jest mały).
Jeśli używasz #import
lub #include
zamiast tego, kompilujesz dużo więcej pracy niż jest to konieczne. Wprowadzasz również złożone zależności nagłówka. Możesz to porównać do algorytmu brutalnej siły. Podczas #import
przeciągania ton niepotrzebnych informacji, które wymagają dużej ilości pamięci, dyskowych operacji we / wy i procesora do przeanalizowania i skompilowania źródeł.
ObjC jest bardzo zbliżony do ideału dla języka opartego na języku C, jeśli chodzi o zależność, ponieważ NSObject
typy nigdy nie są wartościami - NSObject
typy są zawsze wskaźnikowymi licznikami odniesienia. Dzięki temu możesz uniknąć niesamowicie szybkich czasów kompilacji, jeśli odpowiednio ustrukturyzujesz zależności programu i przekażesz je tam, gdzie to możliwe, ponieważ wymagana jest bardzo niewielka zależność fizyczna. Możesz także zadeklarować właściwości w rozszerzeniach klas, aby dodatkowo zminimalizować zależność. To ogromny bonus dla dużych systemów - znałbyś różnicę, gdybyś kiedykolwiek opracował dużą bazę kodu C ++.
Dlatego zalecam, aby w miarę możliwości używać naprzód, a następnie #import
tam, gdzie występuje fizyczna zależność. Jeśli zobaczysz ostrzeżenie lub inne wskazujące na fizyczną zależność - napraw je wszystkie. Poprawka znajduje się #import
w pliku implementacji.
Podczas budowania bibliotek prawdopodobnie sklasyfikujesz niektóre interfejsy jako grupę, w którym to przypadku zrobiłbyś #import
bibliotekę, w której wprowadzono zależność fizyczną (np #import <AppKit/AppKit.h>
.). Może to wprowadzić zależność, ale opiekunowie bibliotek często potrafią obsłużyć fizyczne zależności w zależności od potrzeb - jeśli wprowadzą funkcję, mogą zminimalizować wpływ, jaki ma ona na twoje kompilacje.