从 Any 投射时 UIColor 子类崩溃?
UIColor-subclass crashes when casting from Any?
我知道,不推荐使用 subclassing UIColor
。苹果说
Most developers have no need to subclass UIColor
但我知道。更多关于为什么可以从我昨天发布的 中找到。
那个特定的问题已经解决了,但是我遇到了另一个问题。
假设我有这个自定义颜色 class:
class MyColor:UIColor{
convenience init(test:String){
self.init(red: 0, green: 0, blue: 0, alpha: 1)
}
}
//Then do this anywhere:
let myColor = MyColor(test: "test")
let temp:Any? = myColor
let c = temp as! MyColor
这会崩溃。它崩溃是因为它无法将 temp
转换为 MyColor
:
Could not cast value of type 'UIDeviceRGBColor' (0x..) to 'MyColor' (0x..)
myColor
是 MyColor
的实例。这个相同的实例存储在类型 Any?
的变量中,然后转换回 MyColor
。但它不能。
不过,如果我将其转换为 UIColor
,一切正常。但我不能这样做(在上一个问题中解释过)。
为什么这行不通?
问题是 UIColor
被实现为所谓的 class 集群 。这是一种 class 工厂,但工厂在幕后 隐式 工作。
在您的示例中,如果您 意味着 创建一个 MyColor
实例,则内部发生的情况如下:
MyColor.init
调用super的初始化器class
- 超级 class 然后委托给内部 class 工厂并将具体实现从
MyColor
更改为适合参数的内容,在您的情况下 UIDeviceRGBColor
。
- 这意味着,
UIColor.init
执行 return 与您打算创建的实例不同的实例。这是 UIColor
的子 class,但不再是 MyColor
。
在 Objective C 中,您可以更轻松地跟踪此行为:
UIColor *color = [UIColor alloc];
NSLog(@"Address after alloc: %p - class: %@", color, [color class]);
color = [color initWithRed:1.0, green:1.0, blue:1.0, alpha:1.0];
NSLog(@"Address after init: %p - class: %@", color, [color class]);
你应该得到一个不同的地址和 class 在初始化器被调用后。
UIColor is a class cluster use associative references in a category to
add properties! All of the custom init methods on UIColor return a
UIColor* not an id so you can not easily subclass UIColor nor should
you try.
您可以遵循以下两个建议:
1- 扩展
extension UIColor {
convenience init(test:String){
self.init(red: 0, green: 0, blue: 0, alpha: 1)
}
}
let myColor = UIColor(test: "test")
2-作文
class MyColor {
private(set) var color: UIColor
init(test:String) {
color = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
}
}
let myColor = MyColor(test: "test")
let temp:Any? = myColor
let c = temp as! MyColor
我知道,不推荐使用 subclassing UIColor
。苹果说
Most developers have no need to subclass UIColor
但我知道。更多关于为什么可以从我昨天发布的
假设我有这个自定义颜色 class:
class MyColor:UIColor{
convenience init(test:String){
self.init(red: 0, green: 0, blue: 0, alpha: 1)
}
}
//Then do this anywhere:
let myColor = MyColor(test: "test")
let temp:Any? = myColor
let c = temp as! MyColor
这会崩溃。它崩溃是因为它无法将 temp
转换为 MyColor
:
Could not cast value of type 'UIDeviceRGBColor' (0x..) to 'MyColor' (0x..)
myColor
是 MyColor
的实例。这个相同的实例存储在类型 Any?
的变量中,然后转换回 MyColor
。但它不能。
不过,如果我将其转换为 UIColor
,一切正常。但我不能这样做(在上一个问题中解释过)。
为什么这行不通?
问题是 UIColor
被实现为所谓的 class 集群 。这是一种 class 工厂,但工厂在幕后 隐式 工作。
在您的示例中,如果您 意味着 创建一个 MyColor
实例,则内部发生的情况如下:
MyColor.init
调用super的初始化器class- 超级 class 然后委托给内部 class 工厂并将具体实现从
MyColor
更改为适合参数的内容,在您的情况下UIDeviceRGBColor
。 - 这意味着,
UIColor.init
执行 return 与您打算创建的实例不同的实例。这是UIColor
的子 class,但不再是MyColor
。
在 Objective C 中,您可以更轻松地跟踪此行为:
UIColor *color = [UIColor alloc];
NSLog(@"Address after alloc: %p - class: %@", color, [color class]);
color = [color initWithRed:1.0, green:1.0, blue:1.0, alpha:1.0];
NSLog(@"Address after init: %p - class: %@", color, [color class]);
你应该得到一个不同的地址和 class 在初始化器被调用后。
UIColor is a class cluster use associative references in a category to add properties! All of the custom init methods on UIColor return a UIColor* not an id so you can not easily subclass UIColor nor should you try.
您可以遵循以下两个建议:
1- 扩展
extension UIColor { convenience init(test:String){ self.init(red: 0, green: 0, blue: 0, alpha: 1) } } let myColor = UIColor(test: "test")
2-作文
class MyColor { private(set) var color: UIColor init(test:String) { color = UIColor(red: 0, green: 0, blue: 0, alpha: 1) } } let myColor = MyColor(test: "test") let temp:Any? = myColor let c = temp as! MyColor