Header yang Disegmentasi

File {i>header<i} yang dihasilkan J2ObjC dibagi menjadi beberapa segmen dan dapat dimasukkan satu segmen pada satu waktu. Satu segmen dibuat untuk setiap jenis Java yang diterjemahkan, sehingga setiap class dalam akan memiliki segmennya sendiri. Makro praprosesor digunakan untuk memberi tahu compiler agar hanya membaca segmen tertentu saat menyertakan header.Header tersegmentasi memecahkan masalah siklus penyertaan dalam header yang dihasilkan J2ObjC, yang dijelaskan secara mendetail di bawah ini.

Yang perlu Anda ketahui

  • Gunakan #include, bukan #import untuk menyertakan header yang dihasilkan J2ObjC.
    • Penggunaan #import dengan header tersegmentasi akan bermasalah karena compiler akan melewati pembacaan header jika sudah melihatnya. Namun, karena header tersegmentasi, header mungkin tidak diurai sepenuhnya oleh compiler untuk pertama kalinya.
  • Header yang disegmentasikan dapat dinonaktifkan dengan tanda --no-segmented-headers.

Meliputi Melingkar

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

Anda dapat menghasilkan siklus include dalam file header yang dihasilkan J2ObjC. Untuk mendapatkan siklus seperti itu, kami memerlukan class dalam file A yang memperluas class dalam file B, dan class dalam file B yang memperluas class dalam file A. Skenario ini jarang terjadi, tetapi terjadi di codebase Guava (dan di tempat lain).

Perbaikan alami untuk masalah ini mungkin adalah menampilkan file header terpisah untuk setiap jenis Java yang ditemukan dalam file .java. Namun, J2ObjC dirancang untuk digunakan sebagai alat build, dan semua sistem build yang baik bergantung pada 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
~~~~~~~~~~~~~~   ^

Berikut adalah versi tersegmentasi dari 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")