UIView.init() 的文档在哪里可以找到?

9
在下面的示例中:
import UIKit

class MyView: UIView
{
    override init(frame: CGRect) {
       super.init(frame: frame)
       print ("...init with frame")
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print("...init with coder")
    }
}

.......

 let var = MyView() //  "...init with frame" gets printed

所以看起来MyView()调用了UIView.init(),而UIView.init()又调用了init(frame: CGRect)
但是根据UIView文档,只有一个init(frame:)(和init:coder)。
根据NSObject的文档init()不进行任何初始化操作,只是返回self。
因此必须有一个UIView.init()覆盖了NSObject.init(),然后调用了init(frame:)。但是这个UIView.init()没有被记录在文档中?还是我错过了这篇文档?
3个回答

6

我没有找到关于UIView.init的文档,但UIView.init确实存在。如果在print ("...init with frame")处设置断点,您将在Debug Navigator中看到对[UIView init]的调用。汇编代码清楚地显示它使用CGRectZero作为帧调用objc_msgSendinitWithFrame:

UIKit`-[UIView init]:
    0x10b3ba160 <+0>:  pushq  %rbp
    0x10b3ba161 <+1>:  movq   %rsp, %rbp
    0x10b3ba164 <+4>:  subq   $0x20, %rsp
    0x10b3ba168 <+8>:  movq   0xc52f71(%rip), %rsi      ; "initWithFrame:"
    0x10b3ba16f <+15>: movq   0xcd5f72(%rip), %rax      ; (void *)0x000000010f732690: CGRectZero
    0x10b3ba176 <+22>: movq   0x18(%rax), %rcx
    0x10b3ba17a <+26>: movq   %rcx, 0x18(%rsp)
    0x10b3ba17f <+31>: movq   0x10(%rax), %rcx
    0x10b3ba183 <+35>: movq   %rcx, 0x10(%rsp)
    0x10b3ba188 <+40>: movq   (%rax), %rcx
    0x10b3ba18b <+43>: movq   0x8(%rax), %rax
    0x10b3ba18f <+47>: movq   %rax, 0x8(%rsp)
    0x10b3ba194 <+52>: movq   %rcx, (%rsp)
    0x10b3ba198 <+56>: callq  *0xcd7042(%rip)           ; (void *)0x000000010c8b9800: objc_msgSend
    0x10b3ba19e <+62>: addq   $0x20, %rsp
    0x10b3ba1a2 <+66>: popq   %rbp
    0x10b3ba1a3 <+67>: retq   

谢谢。这也是我看到的情况。看起来只是缺少文档,我想。iOS中最常见的类之一的初始化程序没有文档,这很奇怪! - Declan
我怀疑苹果公司真的希望鼓励使用其他初始化方法。如果你只使用MyView(frame: CGRectZero),调用树就会更短。 - vacawama

2

UIView.init() 存在 —— 然而,它并没有被公开声明,因为这个声明是继承自 NSObject 类中的。

在 Swift 和 ObjC-bridged-to-Swift 中,一个类不必将从超类继承的方法/属性或通过符合协议而包含的方法/属性声明为公共 API。继承或协议采用意味着该类支持这些方法/属性,但它并不能告诉您关于该类对它们的实现做了什么。要知道这一点,您必须仔细阅读文档。

稍微扩展一下你引用的 doc 中的 NSObject.init()(有些为了强调进行了编辑):

由子类实现,在为其分配内存后立即初始化新对象(接收方)。

NSObject 类中定义的 init() 方法不执行任何初始化操作... (1)

在此方法的自定义实现中,您必须调用 super 的初始化程序,然后初始化并返回新对象... (2)

这段话可能不够清晰(我建议对文档进行错误报告,这样苹果就知道需要改进了),以下是一个快速翻译:
  1. 在“裸”NSObject实例中,init()什么也不做。也就是说,该方法纯粹为子类化而存在。

  2. 子类应调用super并执行自己的初始化。在此处看到“自定义”和“你”的地方,应将其视为子类的实现者——也就是说,“你”在这里既适用于你作为第三方开发人员在应用程序中创建新类,也适用于其他Apple类的作者,他们也是NSObject的子类。(你知道的,几乎所有的类都是这样。)


苹果的API文档似乎只在类声明的方法级别上提供文档,对于从其所有超类继承的数百个方法,如UIView,没有文档,也没有关于每个UIView子类继承的所有方法的文档。
正如其他答案中所指出的那样,UIView的无参初始化器相当于使用init(frame:)并传递CGRect.zero。尽管苹果的文档没有一个地方可以附加描述到UIView.init(),但他们可能会在其他地方讨论继承初始化器的影响(也许在UIView类概述中?)。这可能值得提交另一个文档错误报告。

谢谢您的回复。您帖子中唯一直接回答我的问题的部分是:“The way Apple's API documentation seems to work..inherit from UIView.”这确实是苹果文档的通常工作方式吗?如果是,那么它不应该如此(在我看来)。我已经提交了一个错误报告,感谢您的建议。所有重写的方法(公开地)可在对象上调用,应该有文档记录。例如没有参数的 UiView.init() 现在似乎可以随时更改,如果没有明确的文档记录,会破坏现有的代码。 - Declan
1
@rickster,为什么UIView会继承NSObject的初始化方法?因为UIView定义了自己的指定初始化方法,所以初始化方法的继承被阻止了,是吗? - Verticon
@RobertVaessen 初始化方法就是方法,因此子类像继承其他方法或属性一样继承它们。子类可以更改哪些初始化方法是指定的初始化方法,但这并不会阻止其他初始化方法被继承。 - rickster
UIView应该实际上重写init(),以便能够调用init(frame:)并传递CGRect.zero吗? - undefined

0
如果你在Swift中调用MyView(),那么它意味着调用默认构造函数即init被调用。如果你想像Objective-C中一样调用initWithFrame,则必须像这样调用构造函数:MyView(frame:CGRect)。如需详细了解,请参阅苹果文档。

谢谢,但这不是我问的。 - Declan
请访问 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html 以查看关于初始化的Swift编程语言的概念文档。 - Yogesh Gupta

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