UIColor-subclass crashes when casting from Any?

橙三吉。 提交于 2020-02-24 12:10:08

问题


I know, subclassing UIColor isn't recommended. Apple says

Most developers have no need to subclass UIColor

But I do. More on why can be found from another question I posted yesterday. That particular issue was solved, but I met another problem.

Let's say I have this custom color 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

This crashes. It crashes because it can't cast temp to MyColor:

Could not cast value of type 'UIDeviceRGBColor' (0x..) to 'MyColor' (0x..)

myColor is an instance of MyColor. This same instance is stored in a variable of type Any?, and then cast back to MyColor. But it can't.

Though, if I cast it to UIColor everything works. But I can't do that in my case (explained in the previous question).

Why doesn't this work?


回答1:


The problem is that UIColor is implemented as a so-called class cluster. It's a kind of class factory, but the factory is working implicitly under the hood. In your example, if you mean to create a MyColor instance, what happens internally is the following:

  • MyColor.init calls the initializer of the super class
  • The super class then delegates to a internal class factory and changes the concrete implementation from MyColor into something adequate to the parameters, in your case UIDeviceRGBColor.
  • This means, UIColor.init does return a different instance than the one you intended to create. This is a subclass of UIColor, but not of MyColor any more.

In Objective C, you can trace this behaviour more easily:

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]);

You should get a different address and class after the initalizer has been called.




回答2:


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.

There are two recommendations that you can follow below:

1- Extensions

extension UIColor {

convenience init(test:String){
    self.init(red: 0, green: 0, blue: 0, alpha: 1)
   }
}

let myColor = UIColor(test: "test")

2- Composition

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


来源:https://stackoverflow.com/questions/59747840/uicolor-subclass-crashes-when-casting-from-any

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!