The Swift documentation says that adding initializers in an extension is possible, and the example in the document is about adding an initializer to a struct. Xcode doesn't recognize UIColor
's designated initializer in my convenience initializer:
extension UIColor { convenience init(rawValue red: CGFloat, green g: CGFloat, blue b: CGFloat, alpha a: CGFloat) { // Can not find out the designated initializer here self.init() } }
Any solutions?
As you may know Swift does not allow stored properties into extensions. That's by design: “Extensions may not contain stored properties.”
Creating an extension in Swift Creating extensions is similar to creating named types in Swift. When creating an extension, you add the word extension before the name. extension SomeNamedType { // Extending SomeNamedType, and adding new // functionality to it. }
An initializer is a special type of function that is used to create an object of a class or struct. In Swift, we use the init() method to create an initializer. For example, class Wall { ... // create an initializer init() { // perform initialization ... } }
You can't do it like this, you have to chose different parameter names to create your own initializers/ You can also make then generic to accept any BinaryInteger or BinaryFloatingPoint types:
extension UIColor { convenience init<T: BinaryInteger>(r: T, g: T, b: T, a: T = 255) { self.init(red: .init(r)/255, green: .init(g)/255, blue: .init(b)/255, alpha: .init(a)/255) } convenience init<T: BinaryFloatingPoint>(r: T, g: T, b: T, a: T = 1.0) { self.init(red: .init(r), green: .init(g), blue: .init(b), alpha: .init(a)) } }
let green1 = UIColor(r: 0, g: 255, b: 0, a: 255) // r 0,0 g 1,0 b 0,0 a 1,0 let green2 = UIColor(r: 0, g: 1.0, b: 0, a: 1.0) // r 0,0 g 1,0 b 0,0 a 1,0 let red1 = UIColor(r: 255, g: 0, b: 0) // r 1,0 g 0,0 b 0,0 a 1,0 let red2 = UIColor(r: 1.0, g: 0, b: 0) // r 1,0 g 0,0 b 0,0 a 1,0
Well, if you really, really, really want to override an initialiser, there is a way.
Before you read further: never do this to change UIKit
behaviour. Why? It could confuse the heck out of someone that can't figure out why a UIColor
initialiser isn't doing what it normally does. Only do it to fix a UIKit
bug, or add functionality, etc.
I have used the following to patch several iOS bugs.
extension UIColor { private static var needsToOverrideInit = true override open class func initialize() { // Only run once - otherwise subclasses will call this too. Not obvious. if needsToOverrideInit { let defaultInit = class_getInstanceMethod(UIColor.self, #selector(UIColor.init(red:green:blue:alpha:))) let ourInit = class_getInstanceMethod(UIViewController.self, #selector(UIColor.init(_red:_green:_blue:_alpha:))) method_exchangeImplementations(defaultInit, ourInit) needsToOverrideInit = false } } convenience init(_red: CGFloat, _green: CGFloat, _blue: CGFloat, _alpha: CGFloat) { // This is trippy. We swapped implementations... won't recurse. self.init(red: _red, green: _green, blue: _blue, alpha: _alpha) /////////////////////////// // Add custom logic here // /////////////////////////// } }
This is using the dynamic nature of Objective-C, called from Swift, to swap method definition pointers at runtime. If you don't know what this means, or implications of it, it is probably a good idea to read up on the topic before you use this code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With