为什么UIView既调用init又调用initWithFrame方法?

8

我注意到当我在UIView的子类中覆盖initinitWithFrame:时,两种方法都被调用。尽管我的代码只明确调用了其中一个方法:

TestViewController.m:

@implementation TestViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    View1 *view1 = [[View1 alloc] init];
    [self.view addSubview:view1];
}

@end

View1.m:

@implementation View1

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        NSLog(@"initWithFrame");
    }
    return self;
}

- (id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"init");
    }
    return self;
}

@end

控制台的输出如下:

2013-10-17 12:33:46.209 test1[8422:60b] initWithFrame

2013-10-17 12:33:46.211 test1[8422:60b] init

为什么在调用init之前要先调用initWithFrame方法?


3
可能是为什么两个init方法都会被调用的重复问题,请参见https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW3 - Nitin Gohel
是的,我也不理解这个想法:我理解指定初始化的概念,就像苹果官方文档中所述,但是当我在同一个类中调用init方法,该方法又调用initWithFrame,然后再次调用init方法时(正如Sergey的示例中所述),这种情况必须在我们不覆盖init方法时工作。在Sergey的示例中,避免调用两次init方法的唯一解决方案是在init方法的主体中返回[self initWithFrame:CGRectZero]; - David
3个回答

8

这不是问题。在 UIView 的情况下,[super init] 调用会自动更改为 [super initWithFrame:CGRectZero]。因此,您需要牢记这一点并保持这段代码。


7
原因在于在 View1 initWithFrame: 方法内部调用了 [super initWithFrame:] 方法。 UIView initWithFrame 方法会调用 [self init] 方法。
当你在类内部调用一个方法时,它会调用子类中的方法。所以,当你在 UIView 上调用实例方法(例如 init)时,它会尝试在 View1 上调用 init 方法(如果已经实现了)。
根据下面的答案进行编辑:https://dev59.com/s3jZa4cB1Zd3GeqPZhIp#19423494 假设 view1 是 View1 的一个实例。 调用层次结构如下:
   - [view1(View1) init] 

      - [view1(UIView) init] (called by [super init] inside View1)

        - [view1(View1) initWithFrame:CGRectZero] (called inside [view(UIView) init] )

           - [view1(UIView) initWithFrame:CGRectZero] (called by [super initWithFrame] inside View1) 
              - ...

           - NSLog(@"initWithFrame"); (prints "test1[8422:60b] initWithFrame")

      - NSLog(@"init"); (called inside [view1(View1) init] ; prints "test1[8422:60b] init")

检查面向对象编程中的继承。

http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

http://www.techotopia.com/index.php/Objective-C_Inheritance


OP问为什么在他们明确调用init之后,仍然首先调用了initWithFrame。这并没有回答那个问题。 - Tim
@Jeff 我编辑了我的答案,现在答案应该符合问题 :) - maros
1
也许我的英语不太好,但你在回答的开头就说initWithFrame调用了init。实际上是相反的。 - The Windwaker
为了实现清晰的代码,需要有一个指定的初始化方法。对于UIView来说,它是-initWithFrame:方法,然后最好将-init更改为以下内容: - (instancetype)init {return [self initWithFrame:CGRectZero];} - Sound Blaster

1
下面是两种方法的简要描述,这将清楚地定义为什么init会在initWithFrame之后被调用:
initWithFrame方法做什么?
Initializes and returns a newly allocated NSView object with a specified 
frame rectangle. This method returns the initialize and allocated object. Once it 
returned the below init method will called automatically.

init方法是做什么的?

 Implemented by subclasses to initialize a new object (the receiver) immediately after 
 memory for it has been allocated.So this init method will called only when memory has 
 been allocated to the object by initwithFrame. 

2
OP问为什么在他们明确调用init之后,仍然首先调用了initWithFrame。这并没有回答那个问题。 - Tim

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