Kyle Cronin
Kyle Cronin

Reputation: 79103

How can I define a function in a superclass that will use the subclass's type when subclassed in Swift?

I'm working on an abstraction that lets me create an object and assign some properties all in one expression:

extension UIView {
    func with(_ callback: (UIView) -> Void) -> UIView {
        callback(self)
        return self
    }
}

Usable like so:

let greenView = UIView().with {
    $0.backgroundColor = UIColor.green
}

The problem is that when I subclass UIView (in this case), the with method still wants to deal with UIView objects and not the subclass:

class SettingView: UIView {
    let setting = UISwitch()
}

let activeSettingView = SettingView().with { (view: UIView) in
    let settingView = view as! SettingView // this downcast is required
    settingView.setting.isOn = true
}

Is there any way I can specify the type signature for with so that it'll automatically work with the type of any subclass, and thus no longer require manual downcasting? i.e. like this:

let activeSettingView = SettingView().with { (view: SettingView) in
    settingView.setting.isOn = true
}

I've tried looking into generics and protocol extensions, but I haven't found anything suitable yet.

Upvotes: 0

Views: 97

Answers (1)

Tiran Ut
Tiran Ut

Reputation: 1056

This depends on Swift version In Swift 5.1 you can refer to Self in any class, so just replace UIView with Self

In Swift < 5.1 the only way is to create a protocol like this

protocol Transformable {}

extension Transformable {
    func with(_ callback: (Self) -> Void) -> Self {
        callback(self)
        return self
    }
}    

extension UIView: Transformable {}

Then it should work

With this protocol you can extend any class, but will have problems with mutating structs

To be able to use this with classes and structs just replace with with following

extension Transformable {
    func with(_ callback: (inout Self) -> Void) -> Self {  
        var mutable = self
        callback(&mutable)
        return mutable
    }
}    

Upvotes: 1

Related Questions