Директивы @public, @protected и @private не являются обязательными в Objective-C, они являются подсказками компилятора о доступности переменных. Это НЕ ОГРАНИЧИВАЕТ ВАС в доступе к ним.
пример:
@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 );
...
Компилятор gcc выдает:
Main.m:56:1: предупреждение: переменная экземпляра «y» — это @private; это будет грубая ошибка в будущем
Main.m:57:1: предупреждение: переменная экземпляра «y» — это @private; это будет грубая ошибка в будущем
один раз для каждого ненадлежащего доступа к частному члену y, но все равно компилирует его.
При запуске вы получаете
x = 10 , y = -10
Так что на самом деле от вас НЕ зависит писать код доступа таким образом, но поскольку objc является надмножеством C, синтаксис C работает просто отлично, и все классы прозрачны.
Вы можете настроить компилятор для обработки этих предупреждений как ошибок и залога, но внутренне Objective-C не настроен для такой строгости. Диспетчер динамического метода должен будет проверять область действия и разрешение для каждого вызова ( sloooooowwwww... ), поэтому помимо предупреждения во время компиляции система ожидает, что программист будет соблюдать область действия члена данных.
Есть несколько приемов для обеспечения конфиденциальности участников в Objective-C. Во-первых, убедитесь, что вы поместили интерфейс и реализации вашего класса в отдельные файлы .h и .m соответственно, а элементы данных поместили в файл реализации (файл .m). Тогда файлы, которые импортируют заголовки, не имеют доступа к членам данных, только к самому классу. Затем укажите методы доступа (или нет) в заголовке. Вы можете реализовать функции setter/getter в файле реализации для диагностических целей, если хотите, и они будут вызываться, но прямого доступа к членам данных не будет.
пример:
@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).
...
Компилятор будет выдавать предупреждения за такие вопиющие махинации, но будет продолжать и верить, что вы знаете, что делаете (правда?), и что у вас есть свои причины (а вы?). Кажется, много работы? Склонен к ошибкам? Ура, детка! Сначала попробуйте провести рефакторинг своего кода, прежде чем прибегать к магическим приемам C и подобным операциям с фрикадельками.
Но вот оно. Удачи.
person
Chris Reid
schedule
04.06.2012