从 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..)

myColorMyColor 的实例。这个相同的实例存储在类型 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