Ios: Uiview Subclass Init or Initwithframe:

iOS: UIView subclass init or 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:

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 must call the designated initializer:

Obj-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.

How do I write a custom init for a UIView subclass in Swift?

The init(frame:) version is the default initializer. You must call it only after initializing your instance variables. If this view is being reconstituted from a Nib then your custom initializer will not be called, and instead the init?(coder:) version will be called. Since Swift now requires an implementation of the required init?(coder:), I have updated the example below and changed the let variable declarations to var and optional. In this case, you would initialize them in awakeFromNib() or at some later time.

class TestView : UIView {
var s: String?
var i: Int?
init(s: String, i: Int) {
self.s = s
self.i = i
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}

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

iOS: UIView subclass init will call [super init] then call methods in super class, why it will call [subclass initWithFrame:xx]?

Since initWithFrame: is the designated initializer, apple's implementation of init (which you call when you call [super init]) internally calls the initWithFrame: function and passes in CGRectZero. That is the reason both get called. So the end flow ends up looking like this:

[YourClass init] -> [super init] -> [self initWithFrame:CGRectZero] -> 
[YourClass initWithFrame:CGRectZero] -> [super initWithFrame:CGRectZero]

This is assuming you call [super init] when you override init in YourClass and [super initWithFrame:] when you override initWithFrame.

Why UIView calls both init and initWithFrame?

The reason is that inside View1 initWithFrame: you call [super initWithFrame:].
UIView initWithFrame: calls [self init].

When you call a method inside a class, the method on the very subclass is called.
So, when you call an instance method (e.g. init) on UIView it tries to call the init method on View1 (if it is implemented).

EDIT according to answer below: https://stackoverflow.com/a/19423494/956811

Let the view1 be an instance of View1.

The call hierarchy is:

   - [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")

Check inheritance in OOP.

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

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

How to override both initWithFrame: and initWithCoder: in subclass of UIView?

Pack your special initialization in one method. It can be private (declared in .m).
Then override both initializers and call your init-method from within them.

- (void)myInitialization
{
//do your stuff
}

- (id)initWithFrame:(CGRect)aRect
{
self = [super initWithFrame:aRect];

if (self)
{
[self myInitialization];
}

return self;
}

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

return self;
}

UIView: how to set property before initWithFrame is called?

You can't set a property on the object before you call the initialiser because until that has been called the object does not exist. If the initialiser needs access to a property, you will need to supply it as a parameter (since it is a requirement for successful creation of your object).

- (id)initWithFrame:(CGRect)frame

takes a CGRect parameter because the purpose of this method is to create an instance with a predefined frame; it adds functionality to the default NSObject's - (instancetype) init, so is supplied with the frame parameter to work with.

A UIView needs a frame so it can be layed out on screen and rendered (amongst other things). At some point in the implementation it will perform a call to the default [super init] method and then access self to work with the frame it has been handed. It builds on an existing class.

You are building on the UIView class in that you want to to be able to initialise it with a UIImage. You can either opt to provide a default frame for your subclass:

- (instancetype)initWithImage:(UIImage *)image {

if (self = [super initWithFrame:CGRectMake(0,0,0,0)]) {
self.image = image;
}
}

Or provide a more 'useful' default value (Like UIImageView would do) and take the image dimensions as the default frame:

Initializing a UIImageView Object

- (instancetype)initWithImage:(UIImage *)image

Discussion
This method adjusts the frame of the receiver to match the size of the specified image. It also disables user interactions for the image view by default.

With an initialiser like:

- (instancetype)initWithImage:(UIImage *)image {

if (self = [super initWithFrame:CGRectMake(0,0,image.size.width,image.size.height)]) {
self.image = image;
}
}

Override init method of UIView in swift

In init(subviewColor: UIColor, subViewMessage: String), you aren't calling the designated initializer (as the compiler points out nicely).

If you don't know what designated initializers are, they are initializers that have to be called by the subclass at some point. From the docs:

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

In this case, the designated initializer for UIView is init(frame: CGRect), meaning at some point, your new initializer init(subviewColor: UIColor, subViewMessage: String must call super.init(frame:).

In order to fix this, make the following changes:

init(frame: CGRect, subViewColor: UIColor, subViewMessage: String){

self.subViewColor = subViewColor
self.subViewMessage = subViewMessage
super.init(frame: frame)

}

OR you can call your other initializer in your class which ends up calling the designated initializer.

override init(frame: CGRect) {
super.init(frame: frame) // calls designated initializer
}

convenience init(frame: CGRect, subViewColor: UIColor, subViewMessage: String){

self.subViewColor = subViewColor
self.subViewMessage = subViewMessage
self.init(frame: frame) // calls the initializer above

}

As for the convenience method with simply CustomLoadingView(), you have to add another initializer for that. Add this code to your custom view:

convenience init() {
self.init(frame: DEFAULT_FRAME, subViewColor: DEFAULT_COLOR, subViewMessage: DEFAULT_MESSAGE)
}

If you want to learn more about designated and convenience initializers, read about them here and here.



Related Topics



Leave a reply



Submit