Các tệp tiêu đề do J2ObjC tạo được chia thành các phân đoạn và có thể được đưa vào 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, vì vậy, mỗi lớp bên trong sẽ có một phân đoạn riêng. Macro của trình tiền xử lý được dùng để chỉ cho trình biên dịch chỉ đọc một phân đoạn cụ thể khi đưa vào tiêu đề. Tiêu đề phân đoạn giải quyết vấn đề bao gồm các chu kỳ trong tiêu đề do J2ObjC tạo, được mô tả chi tiết trong tài liệu này.
Những điều bạn cần phải biết
- Sử dụng
#include
thay vì#import
để đưa vào các tiêu đề do J2ObjC tạo.- Việc sử dụng
#import
với tiêu đề được phân đoạn sẽ gây ra 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, vì tiêu đề được phân đoạn nên trình biên dịch có thể chưa phân tích cú pháp đầy đủ trong lần đầu tiên.
- Việc sử dụng
- Bạn có thể tắt tiêu đề được phân đoạn bằng cờ
--no-segmented-headers
.
Bao gồm hình tròn
Các tệp tiêu đề do J2ObjC tạo phải sử dụng các phần bao gồm và khai báo chuyển tiếp để giải quyết thông tin loại cần thiết. Bạn nên sử dụng khai báo chuyển tiếp nhiều nhất có thể, tuy nhiên, bạn cần phải thêm các loại được mở rộng hoặc triển khai vì trình biên dịch yêu cầu khai báo đầy đủ về loại.
Bạn có thể tạo các chu kỳ bao gồm trong các tệp tiêu đề do J2ObjC tạo. Để có được một chu kỳ như vậy, chúng ta cần một lớp trong tệp A 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à một trường hợp không phổ biến, nhưng nó xảy ra trong cơ sở mã của Guava (và ở những nơi khác).
Một cách khắc phục tự nhiên cho vấn đề này có thể là phát một tệp tiêu đề riêng cho từng loại Java gặp phải trong tệp .java. Tuy nhiên, J2ObjC được thiết kế để dùng làm công cụ xây dựng và mọi hệ thống xây dựng tốt đều dựa vào kết quả dự đoán được 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 (chưa được 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 được 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 ~~~~~~~~~~~~~~ ^
Các phiên bản 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 (được 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")