Наследование переменных экземпляра в Objective-c

В Objective-c 2.0 почему подклассы должны ссылаться на переменные экземпляра в родительских классах с помощью ключевого слова self?

Рассмотрим следующий пример:

// a.h
@interface MyClass : NSObject
@property (nonatomic, retain) Object *myObject;
@end

// a.m
@implementation MyClass
@synthesize myObject;
@end


// b.h
@interface AnotherClass : MyClass
@end

// b.m
@implementation AnotherClass
- (void) someMethod {
    // error
    // Object *obj = myObject;

    // works
    // Object *obj = self.myObject;
}
@end

Ответ 1

Фактически вы не указали переменную, вы только определили свойство (которое неявно определяет переменную, которая является частной). И поскольку свойство - это просто метод, вам нужен синтаксис точки. Обратите внимание, что self.property совпадает с [self property].

Чтобы исправить это, укажите переменную. Я приведу вам пример, где переменная имеет другое имя, чем свойство. Большинство людей выбрали одно и то же имя для обоих, но мне нравится, чтобы они отличались, поэтому я сразу вижу, какой из них предназначен.

// a.h
@interface MyClass : NSObject {
    // Instance variables are "protected" by default, except if you
    // use @private or @public.
    Object *myObjectVar;
}

@property (nonatomic, retain) Object *myObject;
@end

// a.m
@implementation MyClass
@synthesize myObject = myObjectVar;
@end


// b.h
@interface AnotherClass : MyClass
@end

// b.m
@implementation AnotherClass
- (void) someMethod {
    // works
    Object *obj = myObjectVar;

    // works
    obj = self.myObject;

    // the same as self.myObject
    obj = [self myObject];
}
@end

Обратите внимание на разницу при назначении: если вы назначаете свою переменную, объект не сохраняется автоматически. Но он сохраняется, если вы используете свойство:

myObjectVar = someObject; // not retained, old object not released!
self.myObject = someObject; // old object released, new object retained
[self setMyObject:someObject]; // same as the line above

Изменить: Упомянуто, что синтезированные переменные экземпляра являются закрытыми по умолчанию, как отмечает @Jason Coco. И @NSGod прав, что обычные переменные экземпляра защищены по умолчанию, а не public, исправлены.

Ответ 2

Они не при условии, что вы фактически объявляете переменную экземпляра в суперклассе, а не полагаетесь на новую способность среды выполнения для синтеза переменной экземпляра (в дополнение к синтезу методов доступа). См. Objective-C Язык программирования: Разница времени выполнения для получения дополнительной информации об синтезе переменных экземпляра.

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

@interface MyClass : NSObject
@property (nonatomic, retain) Object *myObject;
@end

в

@interface MyClass : NSObject {
// there is an implied @protected directive here
    Object *myObject;
}

@property (nonatomic, retain) Object *myObject;

@end

По умолчанию переменные экземпляра @protected, что означает, что класс и любые подклассы могут напрямую обращаться к переменным экземпляра. @protected ivars отличаются от @public ivars тем, что вы не можете получить к ним доступ, используя ->. @private Иварцы могут быть доступны только классу, который их объявляет. См. Objective-C Язык программирования: область переменных экземпляра для получения дополнительной информации.