Search code examples
swiftclosuresdry

Create Swift closure to create a UIView


I would like to apply DRY to the lines I'm creating in swift. How can I refactor this code so a closure is called? It resides on a viewcontroller.

var topLineView: UIView = {
    let lineView = UIView()
    lineView.layer.borderWidth = 1.0
    lineView.layer.borderColor = UIColor.lightGray.cgColor
    return lineView
}()

var bottomLineView: UIView = {
    let lineView = UIView()
    lineView.layer.borderWidth = 1.0
    lineView.layer.borderColor = UIColor.lightGray.cgColor
    return lineView
}()

var centerLineView: UIView = {
    let lineView = UIView()
    lineView.layer.borderWidth = 1.0
    lineView.layer.borderColor = UIColor.lightGray.cgColor
    return lineView
}()

I tried creating a variable but that caused an error:

let lineView = {
    let lineView = UIView()
    lineView.layer.borderWidth = 1.0
    lineView.layer.borderColor = UIColor.lightGray.cgColor
    return lineView
}

var centerLineView = lineView()

error (Unable to infer closure type etc...)


Solution

  • Swift isn't able to infer the return type of your closure, so you need to tell it ahead of time that you are returning a UIView. This compiles and runs fine.

    let lineView = { () -> UIView in
        let lineView = UIView()
        lineView.layer.borderWidth = 1.0
        lineView.layer.borderColor = UIColor.lightGray.cgColor
        return lineView
    }
    var myViewFromClosure = lineView()
    var myViewFromClosure2 = lineView()
    var myViewFromClosure3 = lineView()
    

    I personally would opt for a function instead of a closure in this case, however. Like this:

    func lineViewFunc() -> UIView {
        let lineView = UIView()
        lineView.layer.borderWidth = 1.0
        lineView.layer.borderColor = UIColor.lightGray.cgColor
        return lineView
    }
    
    var myViewFromFunc = lineViewFunc()
    var myViewFromFunc2 = lineViewFunc()
    var myViewFromFunc3 = lineViewFunc()