Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle UIView common initialization in swift

Some special classes like UIView have more than one designated initializer.

In Objective-X, we could factor common initialization into a separate function

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

    return self;
}

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

In Swift this is no longer a possibility because the following code results 'self used before super.init call'

override init(frame: CGRect) {
    self.initialize()
    super.init(frame: frame)
}

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

Placing self.initialize after super.init is no help, either, since my entire purpose is initializing members. The following would result in 'property self.X not initialized at super.init call'

var X : Int

override init(frame: CGRect) {
    super.init(frame: frame)
    self.initialize()
}

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

What should i do if i want to factor common initialization in this case? Note that i specifically do not want to use awakeFromNib because i want my objects to be available in any related awakeFromNib implementations in my object hierarchy. Note also that optionals do not make sense for my use case.

like image 405
graveley Avatar asked Sep 30 '14 19:09

graveley


1 Answers

The obvious answer is to call initialize after calling super.init:

override init(frame: CGRect) {
    super.init(frame: frame)
    self.initialize()
}

However, you probably have some instance variables that you want to initialize in the initialize method. The facts are these:

  1. You must initialize all member variables before calling super.
  2. You may not call methods on self (or access computed properties on self) before calling super.init.

The inexorable conclusion is that if you have instance variables you want to initialize in initialize, you must declare each such variable with var, not let, and do one of these things:

  1. Give the instance variable a default value:

    var name: String = "Fred"
    
  2. Make the instance variable Optional, and let it be initialized to nil:

    var name: String?
    
  3. Make the instance variable ImplicitlyUnwrappedOptional, and let it be initialized to nil:

    var name: String!
    

My preference at this point is #2 (make it Optional and initialized to nil).

like image 91
rob mayoff Avatar answered Oct 29 '22 13:10

rob mayoff