The following code is almost exact replica from Apple Documentation and compiles without errors:
guard let firstItem = (rawItems! as? Array<Dictionary<String, Any>>)?.first else {
throw AnError()
}
let identityRef = firstItem[kSecImportItemIdentity as String]
as! SecIdentity? // !!!
guard let identity = identityRef else {
throw AnError()
}
The line marked with !!!
contains forced downcast, while replacing as!
with as
quite obviously results in a compilation error 'Any?' is not convertible to 'SecIdentity?'...
Indeed SecIdentity
is a class while Any
may not even be a class.
What I really cannot explain is the following. If I try to make the code safer, by using this
guard let idenity = firstItem[kSecImportItemIdentity as String] as? SecIdentity
else {
throw AnError()
}
or this
guard let idenityRef = firstItem[kSecImportItemIdentity as String] as? SecIdentity?
else {
throw AnError()
}
I get a compilation error: Conditional downcast to CoreFoundation type 'SecIdentity' will always succeed
SecIdentity
is “an abstract Core Foundation-type object representing an identity, ” and the type of Core Foundation types can be
checked with CFGetTypeID()
. So you can check the type ID first. If it matches the type ID of an
SecIdentity
then the forced cast is safe:
guard let cfIdentity = firstItem[kSecImportItemIdentity as String] as CFTypeRef?,
CFGetTypeID(cfIdentity) == SecIdentityGetTypeID() else {
throw AnError()
}
let identity = cfIdentity as! SecIdentity
See also the bug report SR-7015 The CoreFoundation conditional downcast diagnostic is not as helpful as it should be:
The diagnostic should be updated with a message that informs the developer to compare CFTypeIds (with a fixit if possible).