Header yang Disegmentasi

File header yang dihasilkan J2ObjC dibagi menjadi segmen dan dapat disertakan satu segmen sekaligus. Satu segmen dibuat untuk setiap jenis Java yang diterjemahkan, sehingga setiap class dalam akan memiliki segmennya sendiri. Makro preprocessor digunakan untuk memberi tahu compiler hanya untuk membaca segmen tertentu saat menyertakan header. Header tersegmentasi memecahkan masalah siklus penyertaan dalam header yang dihasilkan J2ObjC, yang dijelaskan secara mendetail dalam dokumen ini.

Yang perlu Anda ketahui

  • Gunakan #include, bukan #import, untuk menyertakan header yang dihasilkan J2ObjC.
    • Menggunakan #import dengan header tersegmentasi akan menimbulkan masalah karena compiler akan melewati pembacaan header jika sudah melihatnya. Namun, karena header tersegmentasi, header mungkin belum sepenuhnya diuraikan oleh compiler untuk pertama kalinya.
  • Header yang tersegmentasi dapat dinonaktifkan dengan flag --no-segmented-headers.

Edaran Mencakup

File header yang dihasilkan J2ObjC harus menggunakan include dan deklarasi forward untuk menyelesaikan informasi jenis yang diperlukan. Deklarasi maju digunakan sebanyak mungkin, tetapi menyertakan diperlukan untuk jenis yang diperluas atau diterapkan karena compiler memerlukan deklarasi jenis lengkap.

Anda dapat membuat siklus penyertaan dalam file header yang dibuat J2ObjC. Untuk mendapatkan siklus tersebut, kita memerlukan class dalam file A yang memperluas class dalam file B, dan class dalam file B yang memperluas class dalam file A. Ini adalah skenario yang tidak mungkin, tetapi terjadi di codebase Guava (dan di tempat lain).

Perbaikan alami untuk masalah ini mungkin dengan memunculkan file header terpisah untuk setiap jenis Java yang ditemukan dalam file .java. Namun, J2ObjC dirancang untuk digunakan sebagai alat build dan sistem build yang baik mengandalkan output yang dapat diprediksi untuk setiap input. Artinya, setiap file .java harus menghasilkan tepat satu file .h dan satu file .m.

Contoh

Foo.java:

class Foo extends Bar {}

Bar.java:

class Bar {
  static class Baz extends Foo {}
}

Foo.h (tidak tersegmentasi):

#ifndef _Foo_H_
#define _Foo_H_

#include "Bar.h"
#include "J2ObjC_header.h"

@interface Foo : Bar
- (instancetype)init;
@end

#endif // _Foo_H_

Bar.h (tidak tersegmentasi):

#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_

Perhatikan bahwa Foo.h menyertakan Bar.h dan Bar.h menyertakan Foo.h. Akibatnya, header ini gagal dikompilasi:

../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
~~~~~~~~~~~~~~   ^

Versi tersegmentasi Foo.h dan Bar.h, yang akan dikompilasi tanpa error:

Foo.h (tersegmentasi):

#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 (tersegmentasi):

#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")