2009-06-08 3 views

ответ

8

Причина в том, что он может вычислять смещения переменных для подклассов.

@interface Bird : NSObject { 
    int wingspan; 
} 
@end 
@interface Penguin : Bird { 
    NSPoint nestLocation; 
    Penguin *mate; 
} 
@end 

Не зная структуру класса «Bird», класс «Пингвин» не может вычислить смещение ее поля от начала структуры. Структура пингвинов выглядит вроде как это:

struct Penguin { 
    int refcount; // from NSObject 
    int wingspan; // from Bird 
    NSPoint nestLocation; // from Penguin 
    Penguin *mate; // from Penguin 
} 

Это имеет побочный эффект: если вы измените размер класса в библиотеке, вы нарушаете все подклассы в приложениях, которые ссылаются на эту библиотеку. Эта проблема связана с новыми свойствами.

6

Несмотря на то, что они объявлены в файле заголовка, все переменные экземпляра в Objective-C по умолчанию имеют защищенный доступ @protected. Это означает, что переменная доступна в классе, который объявляет его и любой класс, наследующий от этого класса.

Вот документация Apple, по определению класса Objective-C: Defining Classes

Обратите внимание на раздел под названием «Сфера переменного экземпляра».

3

Взятые из раздела документации Apple, по определению классов Objective-C, The Role of the Interface:

Although instance variables are most naturally viewed as a matter of the implementation of a class rather than its interface, they must nevertheless be declared in the interface file. This is because the compiler must be aware of the structure of an object where it’s used, not just where it’s defined.

6

Я думаю, что это технический вопрос. Если я правильно понимаю, класс Objective-C - просто причудливая структура C. И для структуры, которую нужно использовать, ее размер должен быть известен. (Как, например, как будет работать sizeof())

+0

Они просто C Структуры , даже не причудливые :-) так что-то вроде anObject-> anIVar работает отлично. К сожалению, устаревшая среда выполнения допускает такой доступ даже по переменным @private и просто рвет предупреждение компилятора: -/ –

2

Обратите внимание, что в рамках нового «Современного времени выполнения» Objective C 2.0 (доступного в приложениях iPhone и 64-разрядных приложениях Mac OS X 10.5) вам не нужно указывать ивары, вы можете указать свойства, а затем использовать @synthesize для генерации ivars.

Это связано с тем, что в современной среде исполнения ivars имеет символ глобальной косвенности, который содержит смещение для ivar. Это также устраняет проблему хрупкого базового класса, позволяя переупорядочивать и добавлять ivars без необходимости перекомпиляции подклассов (удаление или переименование ivars может по-прежнему вызывать ошибки ссылок).

Однако вам по-прежнему нужно перечислить свойства в главном интерфейсе, поэтому, похоже, нет никакого способа полностью скрыть частные ивары, что является неудачным. Вы не можете, например, использовать свойство и @synthesize в категории.

+0

Вы можете, однако, объявить свойство в продолжении и @synthesize в главном @implementation. –

5

В случае, если кто натыкается этим вопрос - по состоянию на XCode 4.2 с компилятором LLVM, вы можете объявить переменный экземпляр в @implementation с помощью следующей распорки обозначения:


@interface SomeClass : NSObject 
@end 

@implementation SomeClass { 
    NSString *myInstanceVariable_; 
} 

- (void)moreMethods {} 
@end 

переменных экземпляра вообще не должен быть частью ваших классов, объявленных публичным интерфейсом - это детали реализации.

Однако УБЕДИТЕСЬ вы определяете переменные экземпляра в фигурных скобках, иначе вы будете определения глобальной переменной, которая не имеет никакого отношения к экземпляру объекта:


@implementation SomeClass 
    NSString *whoopsGlobalVariable_; 

- (void)moreMethods {} 

@end 
+0

Я только что изучал это. Кажется, из моего тестирования пока что GCC не сделает этого; он дает ошибку: «несогласованная спецификация переменных экземпляра». Он только компилируется с LLVM. См. Также [Объявление переменных в @implementation] (http://stackoverflow.com/questions/7946998/declaring-variables-in-implementation). –

+1

Правильно, для этого нужен современный компилятор LLVM. – sickp

Смежные вопросы