Hello Swift Community,

To start, I am new to the mail list so please forgive me for any faux pas I may 
have committed. In addition, please excuse me if this feature has already been 
proposed.

I have noticed, especially with UIKit classes, that I am consistently 
overriding initializers in order to call a setup function. In order to keep the 
class consistent I have to write a bunch of boilerplate code and this becomes 
more of a problem when the number of initializers increase. The code below is a 
simple example of some of the boilerplate needed to write a subclass of 
UIButton.

class MyButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    convenience init() {
        self.init(frame: CGRect.zero)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    private func setup() {
        // Setup for custom class
    }
}

What I am proposing is a setup block that is called after every non-convience 
initializer. The code might look something like the code this:

class MyButton: UIButton {

    convenience init() {
        self.init(frame: CGRect.zero)
    }

    setup {
        // Setup for custom class
    }
}

Every subclass would have a setup block that would be called after ever 
initializer returns, that includes subsequent calls to super class 
initializers. So, a subclass would have a setup block that is called after the 
setup block for the super class is called.

I’m not sure what the best way to implement this would be and I do not have 
intimate knowledge of swift’s compilation process. However, if I were to hack 
it together I would create an intermediate representation that would create 
something like the following:

class MyButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)
        defer {
            setup()
        }
    }

    convenience init() {
        self.init(frame: CGRect.zero)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        defer {
            setup()
        }
    }

    // This should be named something that does not conflict with function 
names that are already defined
    private func setup() {
        // Setup for custom class
    }
}

The defer block is not necessary but it does add an addition layer of 
redundancy and makes the feature more resilient to change. You should also take 
note that setup is not called within the convenience initializer because setup 
will be called within the non-convenience initializer.

Thank you everyone for your time, I look forward to hearing everyones feedback.

-Andrew Arnopoulos
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to