Objective-C:如何从子类访问父属性?

时间:2011-04-07 23:29:11

标签: objective-c cocoa-touch cocoa oop

如果我定义了这个类,如何在没有编译器错误的情况下访问子类中的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中是如何工作的。有人可以启发我吗?

5 个答案:

答案 0 :(得分:53)

您要解决的解决方案是在类扩展中声明MyBaseClass私有属性:

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

然后,您可以在MySubClass中的MyBaseClass 中自由地声明两者。这让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)。子类可以访问其访问者由超类合成的私有属性。我相信这就是你想要实现的目标。

答案 1 :(得分:14)

这就是你如何访问它们。你怎么声明它们是咬你的:

@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(或者假定你是苹果系统目标的子类)应该是基类,除非你非常有经验并且知道根目录是什么。

类扩展通常用于“模拟”私有接口。通过模拟,编译器不强制执行此操作,因为它将在其他语言中强制执行。例如,所有消息仍然是动态的,尽管子类可能(在不知不觉中)覆盖扩展中的方法,如果使用相同的选择器声明的话。

答案 2 :(得分:4)

在您的基类名称之后用()判断,看起来您在类实现中声明了一个私有接口扩展,是这种情况吗?如果是这样,变量只能从该类实现中访问。

你的MyBaseClass是否直接从NSObject继承?

如果是这样,您需要在接口文件中声明someObject属性,如:

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

然后像你现在一样合成它。

答案 3 :(得分:0)

这是满足大多数目标的替代方案。

在标题中,定义界面

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

现在,您可以编辑MyBaseClass中的inheritableObject以及从MyBaseClass继承的任何Class。但是,从外面看,它是只读的。不像@interface MyBaseClass()那样私有,但受到不受控制的更改的保护。

答案 4 :(得分:-3)

super.someObject = nil;。继承意味着MyBaseClass是您的超级类。