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

Objective-C: Как получить доступ к родительским свойствам из подклассов?

Если я определил этот класс, как мне получить доступ к свойству someObject в подклассах без ошибок компилятора?

@interface MyBaseClass
  // someObject property not declared here because I want it to be scoped 
  // protected. Only this class instance and subclass instances should be
  // able to see the someObject property.
@end

// This is a private interface extension...properties declared here
// won't be visible to subclasses. However, I don't see any way to 
// declare protected properties...
@interface MyBaseClass (private)
   @property (nonatomic, readwrite, retain) NSObject *someObject;
@end

@interface MySubclass : MyBaseClass 
@end

@implementation MySubclass

- (id) init {
    // Try to do something with the super classes' someObject property. 
    // Always throws compile errors.

    // Semantic Issue: Property 'someObject' not found 
    // object of type 'MySubclass *'
    self.someObject = nil; 

}
@end



Я, очевидно, не понимаю, как наследование работает в objective-c. Может ли кто-нибудь просветить меня?

4b9b3361

Ответ 1

Следующее решение состоит в том, чтобы объявить частное свойство MyBaseClass в расширении класса:

@interface MyBaseClass ()
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

Затем вы можете сделать это выражение как в MyBaseClass, так и в MySubclass. Это позволяет MySubclass знать об этих свойствах, чтобы его код мог говорить о них.

Если повторение вас беспокоит, поместите расширение класса в собственный файл .h и импортируйте его в оба файла .m.

Я приведу пример из своего собственного кода. Вот MyDownloaderPrivateProperties.h:

@interface MyDownloader ()
@property (nonatomic, strong, readwrite) NSURLConnection* connection;
@property (nonatomic, copy, readwrite) NSURLRequest* request;
@property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
@end

Нет соответствующего файла .m и все, что в этом файле; он как бы чисто декларативный. Теперь вот начало MyDownloader.m:

#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
@implementation MyDownloader
@synthesize connection=_connection;
@synthesize request=_request;
@synthesize mutableReceivedData=_mutableReceivedData;
// ...

И вот начало его подкласса MyImageDownloader.m:

#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"

Проблема решена. Конфиденциальность сохраняется, так как это единственные классы, которые импортируют MyDownloaderPrivateProperties.h, поэтому они являются единственными классами, которые знают об этих свойствах в отношении компилятора (и что вся эта конфиденциальность находится в Objective-C). Подкласс может обращаться к приватным свойствам, чьи аксессоры синтезируются суперклассом. Я считаю, что вы хотели добиться в первую очередь.

Ответ 2

как вы обращаетесь к ним. как вы их объявляете, это то, что вас кусает:

@interface MyBaseClass : NSObject
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

Это обычный способ объявить новый класс objc.

добавив круглые скобки (вместо этого в этом случае объявить суперкласс - NSObject), вы объявили расширение класса, которое, вероятно, не видно подклассу (через включение).

вам, вероятно, никогда не понадобится объявлять корневой класс в objc:

@interface MyBaseClass // << superclass omitted
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

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

Расширения класса

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

Ответ 3

Судя по имени() после имени базового класса, похоже, что вы объявляете расширение частного интерфейса в своей реализации класса, так ли это? Если это так, то переменная будет доступна только из этой реализации класса.

Является ли ваш MyBaseClass наследованием от NSObject напрямую?

Если это так, вам нужно объявить свойство someObject в вашем файле интерфейса, как в:

@interface MyBaseClass : NSObject
{
}
@property (nonatomic, retain) NSObject *someObject;

И затем синтезируйте его, как вы уже делаете.

Ответ 4

Это альтернатива, которая отвечает большинству целей.

В заголовке укажите интерфейс

@interface MyBaseClass : NSObject {
    NSObject *inheritableObject;
}
@property (readonly) NSObject *inheritableObject;

Теперь вы можете редактировать inheritableObject в MyBaseClass, а также в любом классе, который наследуется от MyBaseClass. Однако, снаружи, это только для чтения. Не закрытый, как в случае @interface MyBaseClass(), но защищен от неконтролируемых изменений.

Ответ 5

super.someObject = nil;. Наследование означает, что MyBaseClass - ваш суперкласс.