22

I just updated my xcode to 6.3.1. The problem is I got this weird error message since Swift 1.2. I got this kind of error message

/Users/MNurdin/Documents/iOS/xxxxx/Library/SideBar.swift:32:15: Property 'self.originView' not initialized at super.init call

/Users/MNurdin/Documents/iOS/xxxxx/Library/SideBar.swift:38:20: Immutable value 'self.originView' may only be initialized once

on this code

let originView:UIView?

override init() {
        super.init() //error here

    }

    init(sourceView:UIView, menuItems:Array<String>){
        super.init() //error here
        originView = sourceView //error here
halfer
  • 19,824
  • 17
  • 99
  • 186
Nurdin
  • 23,382
  • 43
  • 130
  • 308
  • 1
    This could be your problem: http://stackoverflow.com/questions/29631800/pass-self-as-argument-within-init-method-in-swift-1-2/29632026#29632026 – ABakerSmith Apr 27 '15 at 08:22

3 Answers3

28

You have to initialize all property before you call super.init in any init method

So,change this before you call super.init()

originView = sourceView //error here

Exception:

  1. optional property
  2. property with default value
  3. lazy property
  • I already initialize my property. check my question. Still error. – Nurdin Apr 27 '15 at 08:56
  • 1
    This answer doesn't quite seem to match the code in the question. The problem in this case isn't where the value is being assigned, the problem is that you can't declare an optional property with `let`. – John Montgomery May 31 '17 at 15:16
16

Make your originView nullable by

var originView: UIView?. 

If your originView is not nullable you have to provide a default value before calling

super.init().
Pratik Patel
  • 439
  • 5
  • 15
Nitheesh George
  • 1,357
  • 10
  • 13
  • 1
    let originView:UIView!. you declared originView as constant using "let". it should "var". when you are using "let" you wont be allowed to change it's value again other than during declaration. – Nitheesh George Apr 27 '15 at 09:00
  • you are correct, sorry my mistake. let me try first. – Nurdin Apr 27 '15 at 09:10
6

From Apple's “The Swift Programming Language” book:

“Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error”

“A designated initializer must ensure that all of the “properties introduced by its class are initialized before it delegates up to a superclass initializer.”

Basically you have to ensure that your instance variables are in a consistent state before you do anything, including calling methods.

class YourClass {
    var view: UIView
    init(view: UIView) {
        self.view = view
    }
}

well in your case you can make it a new UIView:

let originView = UIView()

or make it nullable

let originView: UIView?

or make a lazy property instead:

lazy var originView: UIView = {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 200))
    // customize it
    return view
}()

when using lazy instantiation you can pass a method:

lazy var originView: UIView = self.createView()

func createView() -> UIView {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 200))
        // customize it
        return view
}
Oleh Zayats
  • 2,423
  • 1
  • 16
  • 26
  • What is a better practice? Use *nullable* or *lazy* property? – Edgar May 02 '17 at 17:57
  • 2
    @Edgar it depends really. There's no best way, you need to think how your class should behave, what states should it have and depending on the info you write code. Try to describe your classes on paper first and then code, soon you'll do everything in your mind automatically. – Oleh Zayats May 02 '17 at 18:49