iOS:UIView 子类 init 或 initWithFrame:?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7126726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS: UIView subclass init or initWithFrame:?
提问by ma11hew28
I made a subclass of UIView
that has a fixed frame. So, can I just override init
instead of initWithFrame:
? E.g.:
我制作了一个UIView
具有固定框架的子类。那么,我可以只覆盖init
而不是initWithFrame:
吗?例如:
- (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."
Xcode 文档-initWithFrame:
说:“如果您以编程方式创建视图对象,则此方法是UIView
该类的指定初始化程序。子类可以覆盖此方法以执行任何自定义初始化,但必须super
在其实现的开始时调用。”
What does "designated initializer" mean?
“指定初始值设定项”是什么意思?
回答by Caleb
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.
指定的构造器是所有其他构造器必须调用的构造器。UIView
and 子类有点不寻常,因为它们实际上有两个这样的初始值设定项:-initWithFrame:
and -initWithCoder:
,这取决于视图的创建方式。-initWithFrame:
如果您在代码中实例化视图,并且-initWithCoder:
如果您从笔尖加载它,则应该覆盖。或者,您可以将代码放在第三个方法中并覆盖这两个初始值设定项,以便它们调用您的第三个方法。事实上,这通常是推荐的策略。
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:
因此,举例来说,你可以创建一个UIView子类,ClueCharacter
即拥有自己的初始化方法:-initWithPerson:place:thing:
。然后,您可以像这样创建视图:
Obj-C:
对象-C:
ClueCharacter *mustard = [[ClueCharacter alloc] initWithPerson:@"Col. Mustard"
place:kInTheStudy
thing:kTheRope];
Swift:
迅速:
var mustard = ClueCharacter("Col. Mustard", place: kInTheStudy, thing: kTheRope)
That's fine, but in order to initialize the UIView part of the object, your method mustcall the designated initializer:
没关系,但是为了初始化对象的 UIView 部分,您的方法必须调用指定的初始化程序:
Obj-C:
对象-C:
-(id)initWithPerson:(NSString*)name place:(CluePlace)place thing:(ClueWeapon)thing
{
if ((self = [super initWithFrame:CGRectMake(0, 0, 150, 200)])) {
// your init stuff here
}
}
Swift:
迅速:
func init(name: String, place : CluePlace, thing : ClueWeapon)
{
if (self = super.init(CGRectMake(0, 0, 150, 200))) {
// your init stuff here
}
}
If you want to call your subclass's initializer -init
, that's okay as long as you call -initWithFrame:
in the implementation.
如果你想调用你的子类的 initializer -init
,只要你-initWithFrame:
在实现中调用就可以了。
回答by ma11hew28
in UIView
calling [super init]
is exactly equal to [super initWithFrame:CGRectZero]
在UIView
调用[super init]
中完全等于[super initWithFrame:CGRectZero]
回答by Tommy
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:
在具有多个初始化器的 Objective-C 类中,指定的初始化器是执行有意义工作的那个。所以,通常你有一个带有一些初始化器的类,比如:
- (id)initWithRect:(CGRect)someRect;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
linkTo:(id)someOtherObject;
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.
在这种情况下,您通常(但并非总是)会说第三个是指定的初始化程序,并将其他两个实现为例如
- (id)initWithRect:(CGRect)someRect
{
return [self initWithRect:someRect setDefaultColour:NO];
}
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
{
return [self initWithRect:someRect setDefaultColour:setDefaultColour
linkTo:nil];
}
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 vanilla init:
that calls initWithFrame:
with your normal dimensions. The normal convention is that you can add new variations on init
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.
在您遵循最佳实践的情况下,您应该实施initWithFrame:
以及使用正常尺寸init:
调用的香草initWithFrame:
。通常的约定是您可以init
在子类中添加新的变体,但不应删除任何变体,并且您始终在指定的初始化程序中进行实际的初始化工作。这允许来自父类的任何初始化方法,您没有提供 Still 的新实现,以便与您的子类适当地工作。