user1951992
user1951992

Reputation:

Swift avoid repeating code in initializer

How can I avoid repeating code between my initialisers? I want the dateFormatter to remain a let constant.

let dateFormatter: NSDateFormatter

init() {
    dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    dateFormatter.timeStyle = .MediumStyle
    super.init(nibName: nil, bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
    dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    dateFormatter.timeStyle = .MediumStyle
    super.init(coder: aDecoder)
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    dateFormatter.timeStyle = .MediumStyle
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}

Upvotes: 5

Views: 521

Answers (4)

vadian
vadian

Reputation: 285064

If this is really the actual code replace the entire code with

lazy var dateFormatter : NSDateFormatter = {
   let formatter = NSDateFormatter()
   formatter.dateStyle = .MediumStyle
   formatter.timeStyle = .MediumStyle
   return formatter
}()

The variable is lazily initialized once when it's accessed the first time

Edit: It's also possible to declare the variable as constant without the lazy attribute.

let dateFormatter : NSDateFormatter = { ...

The difference is that the formatter is created immediately (not lazily) during the initialization of the instance.

Edit:

In Swift 3 NSDateFormatter has been renamed to DateFormatter
and .MediumStyle to .mediumStyle

Upvotes: 9

Kaz Yoshikawa
Kaz Yoshikawa

Reputation: 1637

If you need to setup a property, then I would go for vadian's way. But your setup code requires some procedure like preparing complex directly structure or preparing image caches, then I like to go for lazy var closure trick. This setup closure executes only once, just like any other lazy var properties are initialized once. So you can write pretty complex enough procedural code here. Don't forget add private then your subclasses won't interfere your business.

class MyViewController: NSViewController {

    init() {
        super.init(nibName: nil, bundle: nil)!
        self.setup()
    }

    override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.setup()
    }

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

    override func encodeWithCoder(aCoder: NSCoder) {
        super.encodeWithCoder(aCoder)
    }

    lazy private var setup: ()->() = {
        // do some complex procedure here!!
        return {}
    }()
}

Upvotes: 0

stefandouganhyde
stefandouganhyde

Reputation: 4544

In this case you could set the default property value of the date formatter using a closure.

Then your property declaration becomes:

let dateFormatter: NSDateFormatter = {
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    dateFormatter.timeStyle = .MediumStyle
    return dateFormatter
}()

and you can remove the date formatter bits from your initialisers.

Upvotes: 3

riik
riik

Reputation: 4448

That's the only way I could think of:

class Sample: UIViewController {
    let dateFormatter: NSDateFormatter = NSDateFormatter()

    init() {
        super.init(nibName: nil, bundle: nil)
        setupDateFormatter()
    }

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

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        setupDateFormatter()
    }

    private func setupDateFormatter() {
        dateFormatter.dateStyle = .MediumStyle
        dateFormatter.timeStyle = .MediumStyle
    }
}

Upvotes: 0

Related Questions