Meine Anfrage lautet wie folgt. Wann verwendet man #import und wann verwendet man @class?
Einfache Antwort: Sie #import
o #include
wenn eine körperliche Abhängigkeit besteht. Ansonsten verwenden Sie Forward-Deklarationen ( @class MONClass
, struct MONStruct
, @protocol MONProtocol
).
Hier sind einige gängige Beispiele für körperliche Abhängigkeit:
- Jeder C- oder C++-Wert (ein Zeiger oder Verweis ist keine physische Abhängigkeit). Wenn Sie eine
CGPoint
als Ivar oder Eigenschaft, muss der Compiler die Deklaration von CGPoint
.
- Ihre Oberklasse.
- Eine Methode, die Sie anwenden.
Wenn ich eine @class-Deklaration verwende, sehe ich manchmal eine allgemeine Compiler-Warnung wie die folgende: "warning: receiver 'FooController' is a forward class and corresponding @interface may not exist."
Der Compiler ist in dieser Hinsicht eigentlich sehr nachsichtig. Er gibt Hinweise (wie den obigen), aber Sie können Ihren Stapel leicht zerstören, wenn Sie sie ignorieren und nicht #import
richtig. Obwohl dies (IMO) der Fall sein sollte, erzwingt der Compiler dies nicht. In ARC ist der Compiler strenger, weil er für die Referenzzählung verantwortlich ist. Was passiert, ist, dass der Compiler auf einen Standardwert zurückgreift, wenn er auf eine unbekannte Methode trifft, die Sie aufrufen. Bei jedem Rückgabewert und Parameter wird angenommen, dass er id
. Daher sollten Sie jede Warnung aus Ihren Codebases entfernen, da dies als physische Abhängigkeit angesehen werden sollte. Dies ist vergleichbar mit dem Aufruf einer C-Funktion, die nicht deklariert ist. In C wird davon ausgegangen, dass die Parameter int
.
Der Grund, warum Sie Forward-Deklarationen bevorzugen würden, ist, dass Sie Ihre Erstellungszeiten um Faktoren reduzieren können, weil es nur eine minimale Abhängigkeit gibt. Bei Forward-Deklarationen sieht der Compiler, dass es einen Namen gibt, und kann das Programm korrekt parsen und kompilieren, ohne die Klassendeklaration oder alle ihre Abhängigkeiten zu sehen, wenn es keine physische Abhängigkeit gibt. Saubere Builds brauchen weniger Zeit. Inkrementelle Builds nehmen weniger Zeit in Anspruch. Sicherlich müssen Sie am Ende etwas mehr Zeit aufwenden, um sicherzustellen, dass alle Header, die Sie benötigen, für jede Übersetzung sichtbar sind, aber das macht sich schnell durch kürzere Build-Zeiten bezahlt (vorausgesetzt, Ihr Projekt ist nicht winzig).
Wenn Sie #import
o #include
stattdessen wird dem Compiler viel mehr Arbeit aufgebürdet, als notwendig ist. Außerdem führen Sie komplexe Header-Abhängigkeiten ein. Man kann dies mit einem Brute-Force-Algorithmus vergleichen. Wenn Sie #import
Wenn Sie den Quellcode nicht kompilieren, ziehen Sie eine Menge unnötiger Informationen hinein, die viel Arbeitsspeicher, Festplatten-E/A und CPU zum Parsen und Kompilieren der Quellen benötigen.
ObjC ist für eine C-basierte Sprache im Hinblick auf Abhängigkeiten nahezu ideal, da NSObject
Typen sind niemals Werte -- NSObject
Typen sind immer referenzierte Zeiger. Sie können also mit unglaublich schnellen Kompilierzeiten auskommen, wenn Sie die Abhängigkeiten Ihres Programms angemessen strukturieren und nach Möglichkeit weiterleiten, da nur sehr wenige physische Abhängigkeiten erforderlich sind. Sie können auch Eigenschaften in den Klassenerweiterungen deklarieren, um die Abhängigkeiten weiter zu minimieren. Das ist ein enormer Vorteil für große Systeme - Sie kennen den Unterschied, den es macht, wenn Sie jemals eine große C++-Codebasis entwickelt haben.
Daher empfehle ich, wenn möglich Vorwärtsbewegungen zu verwenden, und dann #import
wenn eine körperliche Abhängigkeit besteht. Wenn Sie die Warnung oder eine andere sehen, die körperliche Abhängigkeit andeutet - reparieren Sie sie alle. Die Korrektur besteht darin #import
in Ihrer Implementierungsdatei.
Wenn Sie Bibliotheken erstellen, werden Sie wahrscheinlich einige Schnittstellen als Gruppe klassifizieren, in diesem Fall würden Sie #import
diese Bibliothek, in der die physische Abhängigkeit eingeführt wird (z. B. #import <AppKit/AppKit.h>
). Dies kann zu Abhängigkeiten führen, aber die Bibliotheksbetreuer können die physischen Abhängigkeiten bei Bedarf für Sie handhaben - wenn sie eine Funktion einführen, können sie die Auswirkungen auf Ihre Builds minimieren.