2015-05-11 6 views
1

Рассмотрим ниже структуры:Как Objective-C инициализирует свойство C struct как свойство?

typedef struct _Index { 
    NSInteger category; 
    NSInteger item; 
} Index; 

Если я использую эту структуру как свойство:

@property (nonatomic, assign) Index aIndex;

Когда я к нему доступ без инициализации сразу после контроллера просмотра alloc init, LLDB печатать как:

(lldb) po vc.aIndex 
(category = 0, item = 0) 
(lldb) po &_aIndex 
0x000000014e2bcf70 

Я немного смущен, структура уже имеет действительный адрес памяти, даже до того, как я хочу выделить его. Objective-C автоматически инициализирует структуру? Если это NSObject, я должен сделать alloc init, чтобы получить действительный объект, но для C struct я получаю правильную структуру еще до того, как попытался ее инициализировать.

Может ли кто-нибудь объяснить, и все в порядке, а не вручную его инициализировать?

ответ

0

Семантика свойства заключается в том, чтобы скопировать struct, поэтому его не нужно выделять и инициализировать, как объект Objective-C. Это дает свое собственное пространство, как примитивный тип.

Вы должны быть осторожны, обновляя его, так как это не будет работать:

obj.aIndex.category = 1; 

Вместо этого вам нужно будет сделать это:

Index index = obj.aIndex; 
index.category = 1; 
obj.aIndex = index; 

Это происходит потому, что свойство геттер вернется a копияstruct и не ссылка на нее (первый фрагмент похож на второй фрагмент, без последней строки, которая присваивает копию назад объекту).

Таким образом, вам может быть лучше сделать его объектом первого класса, в зависимости от того, как он будет использоваться.

+0

Я не понимаю, почему я не могу использовать 'obj.aIndex.category = 1;' – Wingzero

+0

Потому что он установит новую категорию на копии объектов ' aIndex' (так что строка похожа на первые 2 строки моего второго примера). – trojanfoe

+1

Я попробовал, и он выдает ошибку компилятора, говоря, что выражение не назначается. По-твоему, по-твоему? – Wingzero

2

Чтобы ответить на подвопрос, почему вы не можете присвоить структурный компонент возвращается из геттера: (как мотивация это, потому что я читал эту Q несколько раз.)

A. Это не имеет никакого отношения к делать с Cbjective-C. Это поведение указано в стандарте C. Вы можете проверить это для простого кода C:

NSMakeSize(1.0, 2.0).width = 3.0; // Error 

B. Нет, это не улучшение компилятора. Если бы это было так, предупреждение было бы результатом, а не ошибкой. Разработчик компилятора не имеет права решать, что такое ошибка. (Есть некоторые случаи, в которых они имеют свободу, но это явно упомянуто.)

C. Причина этой ошибки довольно легко:

Уступка к выражению

NSMakeSize(1.0, 2.0).width 

будет легальным, если это выражение является значением l.Результат A . оператора является L-значением, если структура представляет собой L-значение:

A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,82) and is an lvalue if the first expression is an lvalue.

ИСО/МЭК 9899: ТС3, 6.5.2.3

Поэтому было бы назначаемый, если выражение

NSMakeSize(1.0, 2.0) 

является l-значением. Это не. Причина немного сложнее. Для того, чтобы понять, что вы должны знать связь между ., -> и &:

В отличие от ., -> всегда является л-значение.

A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue. 83)

Поэтому - это то, что сноска 83 объясняет - ->, & и . есть ссылка:

Если вы можете вычислить адрес структуры S, имеющей компонент С с оператором &, то выражение (&S)->C эквивалентно S.C. Это требует, чтобы вы могли вычислить адрес S. Но вы не можете сделать это с возвращаемым значением, даже это простое число ...

int f(void) 
{ 
    return 1; 
} 

f()=5; // Error 

... или указатель ...

int *f(void) 
{ 
    return NULL; 
} 

f()=NULL; // Error 

Вы всегда получаете ту же ошибку: он не может быть назначен. Потому что это r-значение. Это очевидно, потому что неясно,

a) является ли способ, которым компилятор возвращает значение, например. делает ли он это в адресном пространстве.

б) когда время время жизни возвращаемого значения над

Возвращаясь к структуре, что означает, что возвращаемое значение является т-значение. Поэтому результатом оператора . является r-значение. Вам не разрешено присваивать значение r-значению.

Д. Раствор

Существует решение, чтобы присвоить «возвращаемой структуры». Можно решить, хорошо это или нет. Поскольку -> всегда является значением l, вы можете вернуть указатель на структуру. Разыменование этого указателя с оператором -> всегда L-значение, как результат, так что вы можете присвоить ему значение:

// obj.aIndex returns a pointer 
obj.aIndex->category = 1; 

Вам не нужно @public для этого. (Что действительно плохой идеей.)

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