Các chỉ thị @public, @protected, và @private là không ràng buộc trong Objective-C, họ là trình biên dịch gợi ý về khả năng tiếp cận của các biến. Nó KHÔNG HÃY ĐỪNG BẠN truy cập chúng.
dụ:
@interface Example : Object
{
@public
int x;
@private
int y;
}
...
...
id ex = [[Example alloc ] init];
ex->x = 10;
ex->y = -10;
printf(" x = %d , y = %d \n", ex->x , ex->y);
...
Trình biên dịch gcc spits ra:
Main.m: 56: 1: cảnh báo: Ví dụ biến ‘y’ là @private; đây sẽ là một lỗi khó khăn trong tương lai
Main.m: 57: 1: cảnh báo: biến cá thể ‘y’ là @private; đây sẽ là một lỗi khó khăn trong tương lai
một lần cho mỗi truy cập "ko hợp phá" để "private" viên y, nhưng biên dịch nó anyway.
Khi chạy bạn sẽ có được
x = 10 , y = -10
Vì vậy, nó thực sự là tùy thuộc vào bạn KHÔNG phải viết mã truy cập theo cách này, nhưng vì objc là một superset của C, C cú pháp làm việc tốt, và tất cả các lớp trong suốt.
Bạn có thể đặt trình biên dịch xử lý các cảnh báo này là lỗi và bảo lãnh - nhưng mục tiêu-C không được thiết lập nội bộ cho loại độ nghiêm ngặt này. Phương thức động sẽ phải kiểm tra phạm vi và sự cho phép cho mỗi cuộc gọi (slooooowwwww ...), vì vậy ngoài một cảnh báo thời gian biên dịch, hệ thống mong đợi lập trình viên tôn trọng phạm vi thành viên dữ liệu.
Có một số thủ thuật để nhận quyền riêng tư của các thành viên trong mục tiêu-C. Một là đảm bảo rằng bạn đặt giao diện và triển khai lớp của bạn trong các tệp .h và .m riêng biệt, tương ứng và đặt các thành viên dữ liệu vào tệp triển khai (tệp .m). Sau đó, các tệp nhập tiêu đề không có quyền truy cập vào các thành viên dữ liệu, chỉ có chính lớp đó. Sau đó, cung cấp các phương thức truy cập (hoặc không) trong tiêu đề. Bạn có thể thực hiện các hàm setter/getter trong tệp triển khai cho các mục đích chẩn đoán nếu bạn muốn và chúng sẽ được gọi, nhưng quyền truy cập trực tiếp vào các thành viên dữ liệu sẽ không được.
dụ:
@implementation Example2 :Object
{
//nothing here
}
double hidden_d; // hey now this isn't seen by other files.
id classdata; // neither is this.
-(id) classdata { return [classdata data]; } // public accessor
-(void) method2 { ... }
@end
// this is an "informal category" with no @interface section
// these methods are not "published" in the header but are valid for the class
@implementation Example2 (private)
-(void)set_hidden_d:(double)d { hidden_d = d; }
// You can only return by reference, not value, and the runtime sees (id) outside this file.
// You must cast to (double*) and de-reference it to use it outside of this file.
-(id) hidden_d_ptr { return &hidden_d;}
@end
...
[Main.m]
...
ex2 = [[Example2 alloc] init];
double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’
id data = [ex2 classdata] // OK
[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:'
double* dp = [ex2 hidden_d_ptr]; // (SO UGLY) warning: initialization from incompatible pointer type
// use (double*)cast -- <pointer-to-pointer conversion>
double d = (*dp); // dereference pointer (also UGLY).
...
Trình biên dịch sẽ phát đi cảnh báo cho shenanigans trắng trợn như vậy, nhưng sẽ đi trước và tin tưởng rằng bạn biết những gì bạn đang làm, và rằng bạn có lý do của bạn (làm (thực sự?) bạn?). Có vẻ như rất nhiều công việc? Lỗi dễ bị? Yay Baby! Hãy thử tái cấu trúc mã của bạn trước khi sử dụng các thủ thuật ma thuật C và phẫu thuật thịt viên như thế này.
Nhưng đúng vậy. Chúc may mắn.
Cụ thể, trình biên dịch được đề cập có vẻ là Clang> 2. (Hiện tại) GCC sẽ không làm điều đó. –
Trong ngữ cảnh này, 'Clang' giống như 'LLVM', phải không? –
@ranReloaded - no. Có gcc - gcc front & backend, gcc-llvm - gcc frontend, llvm backend - và clang - clang frontend, llvm backend. Tôi chỉ thử nghiệm trên clang, Josh thử nghiệm trên một trong những gcc của. YMMV, chỉ cần thử nó với bất kỳ trình biên dịch bạn đang sử dụng và xem. – CRD