iOS:UIView 子类 init 或 initWithFrame:?
我创建了一个具有固定框架的 UIView 子类。那么,我可以重写 init
而不是 initWithFrame:
吗?例如:
- (id)init {
if ((self = [super initWithFrame:[[UIScreen mainScreen] bounds]])) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
-initWithFrame:
的 Xcode 文档说:“如果以编程方式创建视图对象,则此方法是 UIView
类的指定初始值设定项。子类可以重写此方法执行任何自定义初始化,但必须在实现开始时调用 super
。”
“指定初始化器”是什么意思?
I made a subclass of UIView
that has a fixed frame. So, can I just override init
instead of initWithFrame:
? E.g.:
- (id)init {
if ((self = [super initWithFrame:[[UIScreen mainScreen] bounds]])) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
The Xcode documentation for -initWithFrame:
says: "If you create a view object programmatically, this method is the designated initializer for the UIView
class. Subclasses can override this method to perform any custom initialization but must call super
at the beginning of their implementation."
What does "designated initializer" mean?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
指定的初始化器是所有其他初始化器都必须调用的初始化器。
UIView
和子类有点不寻常,因为它们实际上有两个这样的初始化器:-initWithFrame:
和-initWithCoder:
,具体取决于如何实现视图已创建。如果您在代码中实例化视图,则应覆盖-initWithFrame:
;如果您从笔尖加载视图,则应覆盖-initWithCoder:
。或者,您可以将代码放在第三个方法中并重写这两个初始值设定项,以便它们调用您的第三个方法。事实上,这通常是推荐的策略。因此,例如,您可以创建一个 UIView 子类
ClueCharacter
,它有自己的初始化方法:-initWithPerson:place:thing:
。然后,您可以像这样创建视图:Obj-C:
Swift:
没问题,但是为了初始化对象的 UIView 部分,您的方法必须调用指定的初始化程序:
Obj-C:
Swift:
如果你想调用子类的初始化器
-init
,只要在实现中调用-initWithFrame:
就可以了。The designated initializer is the one that all the other initializers must call.
UIView
and subclasses are a little unusual in that they've actually got two such initializers:-initWithFrame:
and-initWithCoder:
, depending on how the view is created. You should override-initWithFrame:
if you're instantiating the view in code, and-initWithCoder:
if you're loading it from a nib. Or, you could put your code in third method and override both those initializers such that they call your third method. In fact, that's often the recommended strategy.So, for example, you might create a UIView subclass,
ClueCharacter
, that has its own initialization method:-initWithPerson:place:thing:
. You then create your view like this:Obj-C:
Swift:
That's fine, but in order to initialize the UIView part of the object, your method must call the designated initializer:
Obj-C:
Swift:
If you want to call your subclass's initializer
-init
, that's okay as long as you call-initWithFrame:
in the implementation.在
UIView
中调用[super init]
完全等于[super initWithFrame:CGRectZero]
in
UIView
calling[super init]
is exactly equal to[super initWithFrame:CGRectZero]
在具有多个初始化程序的 Objective-C 类中,指定的初始化程序是执行有意义的工作的初始化程序。因此,通常你有一个带有一些初始化程序的类,例如:
在这种情况下,你通常(但并非总是)说第三个是指定的初始化程序,并实现其他两个,例如
如果一个类只有一个初始化程序,那么这是指定的初始化程序。
在您的情况下,要遵循最佳实践,您应该实现
initWithFrame:
以及使用正常尺寸调用initWithFrame:
的普通init:
。通常的约定是,您可以在子类中的init
上添加新的变体,但不应删除任何变体,并且您始终在指定的初始化程序中执行实际的初始化工作。这允许您未提供新实现的父类中的任何初始化方法仍然可以与您的子类正常工作。In an Objective-C class with multiple initialisers, the designated initialiser is the one that does the meaningful work. So, often you have a class with a few initialisers, say:
In that case you'd normally (but not always) say that the third was the designated initialiser, and implement the other two as e.g.
If a class has only one initialiser then that's the designated initialiser.
In your case to follow best practice you should implement
initWithFrame:
and also a vanillainit:
that callsinitWithFrame:
with your normal dimensions. The normal convention is that you can add new variations oninit
in subclasses, but shouldn't take any away, and that you always do the actual initialising work in the designated initialiser. That allows any initialising methods from the parent class that you don't provide new implementations of still to work appropriately with your subclass.