Von J2ObjC generierte Headerdateien sind in Segmente unterteilt und können jeweils einzeln eingeschlossen werden. Für jeden übersetzten Java-Typ wird ein Segment erstellt. Jede innere Klasse hat also ein eigenes Segment. Mithilfe von Makros des Präprozessors wird dem Compiler mitgeteilt, beim Einfügen des Headers nur ein bestimmtes Segment zu lesen. Segmentierte Header lösen das Problem von Include-Schleifen in von J2ObjC generierten Headern, das in diesem Dokument ausführlich beschrieben wird.
Was Sie wissen sollten
- Verwenden Sie
#include
anstelle von#import
, um von J2ObjC generierte Header einzubeziehen.- Die Verwendung von
#import
mit segmentierten Headern ist problematisch, da der Compiler das Lesen des Headers überspringt, wenn er ihn bereits gesehen hat. Da der Header jedoch segmentiert ist, wurde er möglicherweise beim ersten Mal nicht vollständig vom Compiler geparst.
- Die Verwendung von
- Segmentierte Überschriften können mit dem Flag
--no-segmented-headers
deaktiviert werden.
Im Angebot enthalten
In J2ObjC generierte Headerdateien müssen Includes und Vorwärtsdeklarationen verwenden, um die erforderlichen Typinformationen aufzulösen. Vorwärtsdeklarationen werden nach Möglichkeit verwendet. Für erweiterte oder implementierte Typen sind jedoch Includes erforderlich, da der Compiler die vollständige Typdeklaration benötigt.
In J2ObjC generierten Headerdateien können Include-Schleifen generiert werden. Für einen solchen Zyklus benötigen wir eine Klasse in Datei A, die eine Klasse in Datei B erweitert, und eine Klasse in Datei B, die eine Klasse in Datei A erweitert. Dies ist ein unwahrscheinliches Szenario, kommt aber in der Guava-Codebasis (und anderswo) vor.
Eine naheliegende Lösung für dieses Problem wäre, für jeden Java-Typ in einer .java-Datei eine separate Headerdatei auszugeben. J2ObjC ist jedoch als Build-Tool konzipiert und jedes gute Build-System setzt auf vorhersehbare Ausgaben für jede Eingabe. Das bedeutet, dass für jede .java-Datei genau eine .h- und eine .m-Datei generiert werden muss.
Beispiel
Foo.java:
class Foo extends Bar {}
Bar.java:
class Bar {
static class Baz extends Foo {}
}
Foo.h (nicht segmentiert):
#ifndef _Foo_H_
#define _Foo_H_
#include "Bar.h"
#include "J2ObjC_header.h"
@interface Foo : Bar
- (instancetype)init;
@end
#endif // _Foo_H_
Balken.h (nicht segmentiert):
#ifndef _Bar_H_
#define _Bar_H_
#include "Foo.h"
#include "J2ObjC_header.h"
@interface Bar : NSObject
- (instancetype)init;
@end
@interface Bar_Baz : Foo
- (instancetype)init;
@end
#endif // _Bar_H_
Beachten Sie, dass Foo.h Bar.h und Bar.h Foo.h enthält. Daher können diese Header nicht kompiliert werden:
../dist/j2objcc -c Foo.m
In file included from Foo.m:6: In file included from ./Bar.h:9: ./Foo.h:12:18: error: cannot find interface declaration for 'Bar', superclass of 'Foo' @interface Foo : Bar ~~~~~~~~~~~~~~ ^
Segmentierte Versionen von Foo.h und Bar.h, die ohne Fehler kompiliert werden:
Foo.h (segmentiert):
#include "J2ObjC_header.h"
#pragma push_macro("Foo_INCLUDE_ALL")
#if Foo_RESTRICT
#define Foo_INCLUDE_ALL 0
#else
#define Foo_INCLUDE_ALL 1
#endif
#undef Foo_RESTRICT
#if !defined (_Foo_) && (Foo_INCLUDE_ALL || Foo_INCLUDE)
#define _Foo_
#define Bar_RESTRICT 1
#define Bar_INCLUDE 1
#include "Bar.h"
@interface Foo : Bar
- (instancetype)init;
@end
#endif
#pragma pop_macro("Foo_INCLUDE_ALL")
Bar.h (segmentiert):
#include "J2ObjC_header.h"
#pragma push_macro("Bar_INCLUDE_ALL")
#if Bar_RESTRICT
#define Bar_INCLUDE_ALL 0
#else
#define Bar_INCLUDE_ALL 1
#endif
#undef Bar_RESTRICT
#if !defined (_Bar_) && (Bar_INCLUDE_ALL || Bar_INCLUDE)
#define _Bar_
@interface Bar : NSObject
- (instancetype)init;
@end
#endif
#if !defined (_Bar_Baz_) && (Bar_INCLUDE_ALL || Bar_Baz_INCLUDE)
#define _Bar_Baz_
#define Foo_RESTRICT 1
#define Foo_INCLUDE 1
#include "Foo.h"
@interface Bar_Baz : Foo
- (instancetype)init;
@end
#endif
#pragma pop_macro("Bar_INCLUDE_ALL")