范围不正确

时间:2014-05-19 11:31:09

标签: ios objective-c

我有两个班级

A.H

@interface A : UIView

@end

A.M

@implementation A

-(id)initWithCoder:(NSCoder*)aDecoder{
  self = [super initWithCoder:aDecoder];
   if(self){ 
      [self initialize];
   }
return self;
}

-(void)initialize{
 [[NSNotificationCenter defaultCenter]addObserver:self name:keyboardnotificationwillshow];
}
@end

B.h

@interface B : A

@end

@implementation B

-(id)initWithCoder:(NSCoder*)aDecoder{
  self = [super initWithCoder:aDecoder];
   if(self){ 
      [self initialize];
   }
return self;
}

-(void)initialize{
 //do some stuff to prepare B
   [self setBackgroundColor:[UIColor redColor]];
}
@end

现在我把B放在界面构建器中并等待它通过故事板加载 但是!

现在问我的问题:

在以前用于编写代码的所有语言中,我上面写的实现会产生以下内容

  1. 创建B,调用它的initWithCoder方法,看到它需要转到super,转到A的initWithCoder,看到它需要在A中调用initialize(注意初始化是一个发明的方法,而且它是私有的,它是未在两个类的h文件中声明),执行用A
  2. 编写的初始化
  3. 返回self,回到B的initWithCoder看到它需要执行B的初始化,执行B的初始化,将B返回给想用编码器创建它的人
  4. 现在我通过调试运行它,这是实际的结果:  创建B,initWithCoderB - > initWithCoderA - > initializeB - >返回B

    我的实际问题是:为什么它会跳过initializeA?

    记录输出

    2014-05-19 14:45:23.270 MyApp[17780:60b] B initWithCoder
    2014-05-19 14:45:23.270 MyApp[17780:60b] A initWithCoder
    2014-05-19 14:45:23.272 MyApp[17780:60b] B initialize
    2014-05-19 14:45:23.278 MyApp[17780:60b] B initialize
    

    如果我将initializeA重命名为initStuffA,则这是日志输出

    2014-05-19 14:48:41.700 MyApp[17795:60b] B initWithCoder
    2014-05-19 14:48:41.701 MyApp[17795:60b] A initWithCoder
    2014-05-19 14:48:41.701 MyApp[17795:60b] A initialize
    2014-05-19 14:48:41.702 MyApp[17795:60b] B initialize
    

    那么为什么我不能拥有2个与private同名的方法,而没有它们会相互重叠? 因为他们是私人的,我不能称他们为超级

2 个答案:

答案 0 :(得分:3)

由于你重写了B类中的initialize方法,并且在调用initialize方法时创建了一个B类实例,它将指向继承层次结构中最深的实现(在你的例子中是B类的初始化方法) )

答案 1 :(得分:2)

你想在这里实现什么目标?

如果您希望接口B的实例通过接口A的initWithCoder,则无需在接口B中覆盖它。只需将initialize作为公共方法并调用:< / p>

- (void)initialize { [super initialize]; //Any further initialization here }

目前,接口B并不知道它的超类也实现了一个名为initialize的方法,因为它是一个私有方法。

如果接口A中的initWithCoder:方法调用您的initialize方法并且它是一个公共方法,那么当您创建接口B的实例时,它将通过initWithCoder:接口A,然后到接口B的initialize,然后应该调用[super initialize];以确保执行接口A initialize方法中的任何代码。

编辑1:

好的,所以接口B继承自接口A.

默认情况下(即使用空白实现),接口B的实例将与接口A完全相同,因为所有方法都将默认通过接口A中的实现。

作为界面A的孩子的界面B有机会覆盖界面A提供的公开的任何方法或属性。

要公开发布,请在.h文件中声明。

如果你有一个方法,例如在接口A的updateView文件中有.h,那么接口B的实现就有机会覆盖它。如果您希望接口B在自身和接口A中执行操作,则需要使用super关键字调用继承树。例如,在接口B(子代)的实现中具有以下内容:

- (void)updateView { [super updateView]; //This calls any code written in interface A's updateView method //Add your own code here }

这显示了您的子类执行继承,因为它可以访问由接口A​​创建的updateView方法。

接口B,因为它是接口A的子接口,将使用其父类的实现填充任何空方法。在您的示例中,您在两个接口中都实现了initWithCoder:。这是不必要的,并导致重写并发症。通过在接口B中省略initWithCoder:的声明,它将使用接口A的实现,它的父类调用initialize。每次重写方法实现并希望执行自己的代码和父类的代码时,您只需记住调用super。

希望这可以清除你在Objective-C中对继承的一些困惑。