Reputation: 2891
In ObjC:
@protocol Random
+ (instancetype)random;
@end
@interface UIColor (Random)
<Random>
@end
@implementation
+ (instancetype)random {
return [UIColor colorWith...];
}
@end
It works in ObjC, but I can't get it to work in Swift.
In Swift:
protocol Random {
static func randomExample() -> Self
}
extension UIColor: Random {
final class func randomExample() -> UIColor {
return UIColor(red: ...)
}
}
But this throws errors no matter how I configure it.
Upvotes: 2
Views: 1212
Reputation: 3440
ABakerSmith deserves the credit for answering your question but I would like to extend his answer to show how the same protocol applies to the value types of Struct and Enum. Since the value types can not be derived from, their protocol implementation simply uses the type name and not Self.
EDIT: Adding code as requested.
protocol Random {
static func random() -> Self
}
extension Float: Random {
static func random() -> Float {
return Float(arc4random()) / Float(UInt32.max)
}
}
extension CGFloat: Random {
static func random() -> CGFloat {
return CGFloat(Float.random())
}
}
extension UIColor: Random {
static func random() -> Self {
return self.init(
red: CGFloat.random(),
green: CGFloat.random(),
blue: CGFloat.random(),
alpha: 1.0)
}
}
let c1 = UIColor.random()
let c2 = UIColor.random()
let c3 = UIColor.random()
Upvotes: 4
Reputation: 22939
Your problem arises from trying to return a UIColor
from randomExample
, because randomExample
wants you to return Self
.
Take the following incorrect example:
// Here `Self` is `UIColor`.
extension UIColor: Random {
class func randomExample() -> Self {
return UIColor(...) // Here's the problem...
}
}
// Here `Self` is `MyColor`.
class MyColor: UIColor {}
Since randomExample
isn't overriden by MyColor
, randomExample
called by MyColor
would try to return a UIColor
. However, randomExample
is expecting to return MyColor
instance.
To solve this you can do:
extension UIColor: Random {
class func randomExample() -> Self {
// `self` refers to the current class.
// If this wasn't a class method you would use `self.dynamicType`
return self(red: 0, green: 0, blue: 0, alpha: 0)
}
}
let color1 = UIColor.randomExample() // color1 is a `UIColor`.
let color2 = MyColor.randomExample() // color2 is a `MyColor`.
If you're using Swift 2 you need to use:
self.init(red: 0, green: 0, blue: 0, alpha: 0)
You may also be interested in: Protocol func returning Self and Implementing NSCopying in Swift with subclasses.
Upvotes: 4