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

10
//Super class .h file

@interface MySuperClass : NSObject

@end

//Super class .m file

@interface MySuperClass ()

@property (nonatomic, strong) UITextField *emailField; 

@end

@implementation MySuperClass

-(void)accessMyEmailField {

   NSLog(@"My super email: %@", self.emailField.text);

}

@end


// ********** my subclass *******

//Subclass .h file

@interface MySubClass : MySuperClass

@end

//SubClass .m file

@interface MySubClass ()

@end

@implementation MySubClass

-(void)myEmail {

   NSLog(@"My subclass email: %@", self.emailField.text);

}

-(void)setMyEmailFromSubclass{

   self.emailField.Text = @"email@gmail.com"

}

@end
  1. 如何在-(void)myEmail方法中访问emailField?
  2. 如何在Subclass的-(void)setMyEmailFromSubclass方法中设置email,并在super class的accessMyEmailField方法中访问它?
3个回答

9
您可以在第二个头文件中放置这些属性的访问器,并根据需要导入该文件。例如:
mySuperClass+undocumentedProperties.h
#import "mySuperClass.h"

@interface mySuperClass(undocumentedProperties)

  @property (nonatomic, strong) UITextField *emailField;

 @end

mySuperClass.m

#import "mySuperClass+undocumentedProperties.h"

@interface mySuperClass()
///stuff that truly will be private to this class only
// self.emailField is no longer declared here..
@end

@implementation mySuperClass

@synthesize emailField; //(not really needed anymore)

/// etc, all your code unaltered
@end

mySubclass.h

#import "mySuperClass.h"
@interface mySubclass:mySuperClass

///some stuff
@end

mySubclass.m

#import "mySubclass.h"
#import "mySuperClass+undocumentedProperties.h"
@implementation

//off you go, this class is now 'aware' of this secret inherited property..

@end

显然,MySuperClass.m必须导入这个.h文件以及其默认文件(实际上是替代默认文件,因为默认文件已经内置在其中),但是您的子类也可以导入它(直接导入到它们的.m文件中,所以这些属性仍然对该类保持私有)。这不是一个正确的类别,因为没有相应的mySuperClass+undocumentedProperties.m文件(如果尝试这样做,您将无法为这些秘密属性合成备份iVars。享受 :)


1
对我来说有点不太清楚。你能展示一下在我提供的例子中你会怎么做吗? - PashaN
1
如果我只有一个需要内部访问的类,我倾向于将此信息放在另一个类中,以减少文件数量。但是,如果有多个需要半私有访问的类,则这确实是最佳解决方案。 - Kendall Helmstetter Gelner
@KendallHelmstetterGelner 谢谢。今天学到了新东西。 - PashaN
同时,Pasha,这可能很明显,但是在这个“秘密头文件”中,子类也可以轻松地看到未记录的方法/函数原型。例如: -(void)做某事;等等。 - Jef
这是一个类似于我使用的概念,有时候对于来自其他oop语言的人来说并不清晰,需要重新声明和访问超类属性和成员。就像Zaph所解释的那样,“private”成员应该始终保持“private”,不可在其基类范围之外可见。如果我们从其子类访问“super”成员-那么它应该对外界隐藏-我们需要在其他oop语言中称为“PROTECTED”的成员可见性。但我仍然没有找到在Objective-C中复制的干净而好的方法。 - cybercow
是的,我同意。不过,我有可靠消息说,这正是他们在1无限循环做的事情.... - Jef

1

从你的超类中复制你想要的私有接口部分 - 换句话说,在你的子类 .m 文件中,你需要放置:

@interface MySuperClass ()
@property (nonatomic, strong) UITextField *emailField; 
@end

(将其放置在现有的@interface MySubClass()代码之上)

现在你的子类知道该方法存在于超类中并可以使用它,但你没有将它暴露给任何其他人。


2
但这是一个可怕的概念!它们可以被删除或者大幅度改变。超类不应该依赖于子类,但这正是这个概念所导致的,超类不能在不改变使用它们的子类的情况下改变其内部实现。 - zaph
在 .m 子类中 ('@interface MySubClass () @property (nonatomic, strong) UITextField *emailField; @end') 这样我可以设置超类属性,但是在超类中我的 emailField 仍然为空。 - PashaN
Zaph: 我只是说了如何,而不是你是否应该这样做。@Pasha:你可能正在尝试在IB或viewDidLoad之前设置emailField或类似的东西。 - Kendall Helmstetter Gelner
@Zaph 谢谢,伙计。这正是我在寻找的。问题解决了。 - PashaN

1
整个私有属性的意义就在于此,你不应该想要访问它们。因为它们是私有的,所以它们可能会改变或被删除,从而破坏依赖它们的子类。
话虽如此,它们并不是真正的私有,只是没有“发布”。它们可以被调用,因为Objective-C是一种运行时动态语言。

这正是我想做的。我不想让emailField被公开,所以我将其保留在.m文件中,但我需要从子类.m文件中访问它。 - PashaN
2
如果它们都是你的类,请创建两个头文件。一个包含公共声明,另一个包含私有声明。在超类和任何需要它的子类中导入私有和公共内容,但不要使私有头文件对其他人可用。这就是苹果处理公共和私有方法的方式。 - zaph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接