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