Typecast from AnyObject? to CGColor will always succeed

In my app, I have a style dictionary that maps a style key to AnyObject? This allows me to store a CGColor as a value for a style key and all is good. When I want to retrieve the color later I index my dictionary with the appropriate key and try a conditional downcast: If let color = style[kStyle_BackgroundColor] as? CGColor { ... } This gets me an error "Conditional downcast to CoreFoundation type 'CGColor' will always succeed. That strikes me as odd. Trying various other mechanisms for downcasts lead to other errors. This "will always succeed" seems to violate the safety of Swift. Is this error message a bug?

Accepted Reply

The behavior is noted in the Xcode 6.1 Release Notes.

- New Features

Swift Language

Casts can now be performed between CF types (such as

CFString
,
CGImage
, and
SecIdentity
) and
AnyObject
. Such casts will always succeed at run-time. For example:
  • var cfStr: CFString = ...
  • var obj: AnyObject = cfStr as AnyObject
  • var cfStr = obj as CFString


Swift challenges to import CF types as managed object references, but they are originally defined as pointers to private structs in C-language.

So, the original definitions do not contain type hierarchy informations, which are needed for conditional cast in Swift.

In fact, some CF types are actually subtypes of other CF types, but in old Swift, before 1.1, we cannot convert between such two types without using unsafeBitCast or similar unsafe things.


I believe this is a temporary workaround to treat CF types and shoul be improved, but as for now, it's an intended feature, so should not be called as a bug.

Replies

The behavior is noted in the Xcode 6.1 Release Notes.

- New Features

Swift Language

Casts can now be performed between CF types (such as

CFString
,
CGImage
, and
SecIdentity
) and
AnyObject
. Such casts will always succeed at run-time. For example:
  • var cfStr: CFString = ...
  • var obj: AnyObject = cfStr as AnyObject
  • var cfStr = obj as CFString


Swift challenges to import CF types as managed object references, but they are originally defined as pointers to private structs in C-language.

So, the original definitions do not contain type hierarchy informations, which are needed for conditional cast in Swift.

In fact, some CF types are actually subtypes of other CF types, but in old Swift, before 1.1, we cannot convert between such two types without using unsafeBitCast or similar unsafe things.


I believe this is a temporary workaround to treat CF types and shoul be improved, but as for now, it's an intended feature, so should not be called as a bug.

Thanks. In this case I'll use a belt and suspenders approach then


                if let colorValue = topic.style[kTopicStyle_BackgroundColor] {
                    if(CFGetTypeID(colorValue) == CGColorGetTypeID()) {
                        newView.layer?.backgroundColor = (colorValue as! CGColor)
                    }
                }