Protocol Extension Initializer

后端 未结 4 1132
谎友^
谎友^ 2020-12-10 04:34

I would like to know what the protocol equivalent is for an initializer in a simple class that only contains initializing functionality and is only intended to be extended i

4条回答
  •  生来不讨喜
    2020-12-10 05:07

    protocol Thing {
        var color: UIColor {get set}
    }
    

    Awesome, no problems.

    extension Thing {
        init(color: UIColor) {
            self.color = color
        }
    }
    

    No. That's never going to work. This breaks way too many rules. The first and most important is that this doesn't necessarily set all the properties. Consider your NamedThing. What is name in this case? What happens if the color setter fetches other properties that haven't been set yet? The compiler can't see every possible implementation of this yet, so it has no idea if color is just an ivar or something wildly more complicated. No, this isn't going to work.

    The real problem is "an abstract class that can be extended in a concrete class." Forget classes. Forget inheritance. Swift is all about composition and protocols, not inheritance.

    So let's think about the example you describe in the comments (though in Cocoa, there are no "abstract classes," either). Let's assume that setting color is in fact a lot of code that you don't want to duplicate. That's no problem. You just need a function.

    import UIKit
    
    protocol Thing {
        var color: UIColor {get set}
    }
    
    private extension Thing {
        static func colorForColor(color: UIColor) -> UIColor {
            // We don't really use the color directly. We have some complicated code that we don't want to repeat
            return color
        }
    }
    
    final class NamedThing: Thing {
        var name: String
        var color: UIColor
    
        init(name: String, color: UIColor) {
            self.name = name
            self.color = NamedThing.colorForColor(color)
        }
    }
    

    Since the point of your extension is to handle partial initialization, just let it calculate the part you need. Don't try to make it an initializer in an extension, since then it would have to be responsible for initializing everything, and that is very hard to do correctly when you mix it with inheritance.

提交回复
热议问题