Tiêu đề được phân đoạn

Các tệp tiêu đề do J2ObjC tạo được chia thành các phân đoạn và có thể bao gồm một phân đoạn tại một thời điểm. Một phân đoạn được tạo cho mỗi loại Java đã dịch, do đó, mỗi lớp bên trong sẽ có một phân đoạn riêng. Macro bộ xử lý trước được dùng để yêu cầu trình biên dịch chỉ đọc một phân đoạn cụ thể khi bao gồm tiêu đề.Tiêu đề đã phân đoạn giải quyết vấn đề về chu kỳ bao gồm trong tiêu đề do J2ObjC tạo, được mô tả chi tiết dưới đây.

Những điều bạn cần biết

  • Sử dụng #include thay vì #import để bao gồm các tiêu đề do J2ObjC tạo.
    • Việc sử dụng #import với các tiêu đề được phân đoạn sẽ gặp vấn đề vì trình biên dịch sẽ bỏ qua việc đọc tiêu đề nếu đã thấy tiêu đề đó. Tuy nhiên, do tiêu đề được phân đoạn, nên có thể trình biên dịch chưa phân tích cú pháp đầy đủ trong lần đầu tiên.
  • Bạn có thể tắt các tiêu đề đã phân đoạn bằng cờ --no-segmented-headers.

Tròn bao gồm

Các tệp tiêu đề do J2ObjC tạo phải sử dụng các nội dung khai báo bao gồm và chuyển tiếp để giải quyết thông tin cần thiết về loại. Các phần khai báo chuyển tiếp được dùng nhiều nhất có thể, nhưng cần thiết đối với các kiểu được mở rộng hoặc triển khai vì trình biên dịch yêu cầu khai báo kiểu đầy đủ.

Bạn có thể tạo chu kỳ bao gồm trong các tệp tiêu đề được tạo bởi J2ObjC. Để có được chu kỳ như vậy, chúng tôi yêu cầu một lớp trong tệp A (lớp này mở rộng một lớp trong tệp B) và một lớp trong tệp B mở rộng một lớp trong tệp A. Đây là trường hợp ít có khả năng xảy ra, nhưng nó vẫn xảy ra trong cơ sở mã của Guava (và những nơi khác).

Cách khắc phục tự nhiên cho vấn đề này có thể là phát hành một tệp tiêu đề riêng cho từng loại Java gặp trong tệp .java. Tuy nhiên, J2ObjC được thiết kế để sử dụng như một công cụ xây dựng và bất kỳ hệ thống xây dựng tốt nào đều dựa vào đầu ra có thể dự đoán cho mỗi đầu vào. Điều đó có nghĩa là mỗi tệp .java cần tạo đúng một tệp .h và một tệp .m.

Ví dụ:

Foo.java:

class Foo extends Bar {}

Bar.java:

class Bar {
  static class Baz extends Foo {}
}

Foo.h (không phân đoạn):

#ifndef _Foo_H_
#define _Foo_H_

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

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

#endif // _Foo_H_

Bar.h (không phân đoạn):

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

Lưu ý rằng Foo.h bao gồm Bar.h và Bar.h bao gồm Foo.h. Do đó, các tiêu đề này không biên dịch được:

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

Dưới đây là các phiên bản được phân đoạn của Foo.h và Bar.h sẽ biên dịch mà không gặp lỗi.

Foo.h (đã phân đoạn):

#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 (đã phân đoạn):

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