2019-08-23
Crash when setting property in UIColor subclass
stackoverflow
Question

I am currently trying to create a subclass of UIColor, since I need to enrich it with a couple of properties for my purposes. As soon as I try to set any custom properties on my subclass, the app will crash with an EXC_BAD_ACCESS exception. Is this expected? Am I missing something?

This is the code I've tried:

class MyColorClass: UIColor {

    var customProperty: String!

    convenience init(fromColor color: UIColor) {
        self.init(cgColor: color.cgColor)
        self.customProperty = "rgfgb" // crash
    }

}

MyColorClass(fromColor: UIColor.black)

Example playground: https://ufile.io/ejmrwst4

Answer
1

So after digging around a bit, here's what I found out:

What is happening

So it seems it is not easily possible to subclass UIColor, since it is part of a so-called "class cluster". This article describes it really well.

The gist of the matter is that, internally, Apple has several (private) subclasses of UIColor, and UIColor itself is designed as an abstract factory class which returns one of the concrete subclasses to you. Apple describes all this here. Therefore, if you subclass UIColor, some functionality is missing since it's not designed to be used directly.

The solution

Theoretically, it is possible to create a subclass of a class cluster class. Apple describes this in the linked article. It is a pain, though, since you need to implement all methods from UIColor and forward calls to them to a valid UIColor instance. Additionally, I couldn't manage to get this to work with UIColor, since some of its required initializers are defined in an extension, which you cannot override.

Therefore, the easiest way to go is to just create a wrapper class, which wraps a UIColor property. This is not quite as elegant as a subclass, since you cannot use your custom class in place of a UIColor, but it works:

class MyColor {

    var base: UIColor

    ....
}

let myColor = MyColor()
/* we can't use myColor as a UIColor, but have to use myColor.base instead */
Crash when setting property in UIColor subclass
See more ...