Подтвердить что ты не робот

Если подкласс относится к высокому уровню ivar, синтезируется несвязанное свойство

Изменить: Я просто заметил, что этот другой вопрос задал одно и то же: Почему подкласс @property без соответствующего ivar спрятать суперкары ivars?

Это какое-то интересное поведение, которое я не могу найти нигде официально или неофициально (блог, твит, вопрос SO и т.д.). Я довел его до сути и протестировал это в новом проекте Xcode, но я не могу его объяснить.

MyBaseClass имеет переменную экземпляра:

@interface MyBaseClass : NSObject {
    NSObject *fooInstanceVar;
}
@end

MySubclass расширяет MyBaseClass и объявляет полностью несвязанное свойство (то есть свойство не предназначено для поддержки переменной экземпляра):

#import "MyBaseClass.h"
@interface MySubclass : MyBaseClass { }
@property (nonatomic, retain) NSObject *barProperty;
@end

Если реализация MySubclass не синтезирует свойство, а реализует методы доступа, все в порядке (без ошибок компилятора):

#import "MySubclass.h"
@implementation MySubclass

- (NSObject*)barProperty {
    return [[NSObject alloc] init]; // pls ignore flagrant violation of memory rules.
}

- (void)setBarProperty:(NSObject *)obj { /* no-op */ }

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

Но если я удалю методы доступа к свойствам и заменим их объявлением synthesize для свойства, я получаю ошибку компилятора: 'fooInstanceVar' undeclared (first use in this function).

#import "MySubclass.h"
@implementation MySubclass
@synthesize barProperty;

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

Эта ошибка исчезает, если я удаляю объявление synthesize, или если я не ссылаюсь на переменную экземпляра fooInstanceVar из MySubclass.m, или если я поместил все определения интерфейса и реализации в один файл. Эта ошибка также возникает в настройках GCC 4.2 и GCC/LLVM.

Может ли кто-нибудь объяснить, что происходит здесь?

4b9b3361

Ответ 1

Как ответил в этом вопросе: object c xcode 4.0.2: подкласс не может получить доступ к переменным суперкласса "не был объявлен в этой области"

Из документа: Apple Objective-C Программирование Лангаж: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF125

Переменная экземпляра доступна в классе, который объявляет его и внутри классов, которые наследуют его. Все переменные экземпляра без явной директивы scope имеют область @protected.

Однако переменную открытого экземпляра можно получить в любом месте, как если бы это было поле в структуре C. Например:

Рабочий * ceo = [[Рабочий набор] init];

ceo- > boss = nil;

У меня есть ошибка компиляции с использованием LLVM GCC 4.2 (для проекта iOS на устройстве):

error: 'fooInstanceVar' undeclared (сначала использовать в этой функции) и тот же, что и в GCC 4.2: error: 'fooInstanceVar' uneclared (сначала использовать в этой функции)

Я могу скомпилировать с использованием LLVM Compiler 2.0 без ошибок.

Для компиляции с LLVM GCC 4.2 и GCC 4.2 с использованием self- > :

[NSArray arrayWithObjects: self.barProperty, self- > fooInstanceVar, nil]; в методе doSomethingWithProperty.

Ответ 2

Компилятор ведет себя корректно; синтез в подклассах, использующий хранение в суперклассе, является verboten.

В какой-то момент произошла ошибка в этом отношении против llvm. Это может быть в общедоступной базе данных ошибок.

В любом случае, пожалуйста, напишите ошибку, прося пояснить это правило.


Я просто попробовал это, и он компилируется без предупреждения. Что я не делаю?

@interface MyBaseClass : NSObject {
    NSObject *fooInstanceVar;
}
@end

@interface MySubclass : MyBaseClass { }
@property (nonatomic, retain) NSObject *barProperty;
@end

@implementation MyBaseClass
@end

@implementation MySubclass
@synthesize barProperty;

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

Неясно, какую проблему вы пытаетесь решить. Все переменные экземпляра небезопасны везде, но 32-разрядная Mac OS X.

Ответ 3

Я тоже не могу воспроизвести вашу ошибку. У вас установлен флаг флага компилятора не по умолчанию? Не могли бы вы предоставить копию своего проекта? Это определенно кажется ошибкой в ​​компиляторе.

Ознакомьтесь с этой статьей здесь для наилучшего использования @property/@synthesize. Краткое резюме заключается в том, чтобы удалить все ваши ivars из ваших объектов (если вам не нужно использовать 32-битную среду выполнения по какой-либо причине). Тогда используйте только ваши геттеры и сеттеры, вместо того, чтобы напрямую обращаться к синтезированным иварам. После этого можно избежать любых будущих проблем с этой ошибкой.