CFDictionary will not connect to NSDictionary (Swift 2.0 / iOS9)

OK, this is the case that I encountered while working with CGImageSource, and noticed that in some cases the duty-free bridge between CFDictionary and NSDictionary is encountering problems. I managed to build the example below to show what I mean:

func optionalProblemDictionary() -> CFDictionary? { let key = "key" let value = "value" var keyCallBacks = CFDictionaryKeyCallBacks() var valueCallBacks = CFDictionaryValueCallBacks() let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, UnsafeMutablePointer(unsafeAddressOf(key)), UnsafeMutablePointer(unsafeAddressOf(value)), 1, &keyCallBacks, &valueCallBacks) return cfDictionary } 

Pretty simple (and a little dumb), but its function returns an optional CFDictionary. The "fun" begins when you try to create an NSDictionary from this function:

Why won't the following work?

 if let problemDictionary = optionalProblemDictionary() as? NSDictionary { print(problemDictionary) // never enters, no warnings, compiles just fine } 

So far, is this working fine?

 if let cfDictionary = optionalProblemDictionary() { let problemDictionary = cfDictionary as NSDictionary print(problemDictionary) } 

Xcode 7.0 (7A220)

+5
source share
1 answer

CFDictionary? reason that the function returns an optional CFDictionary? and cannot be passed to (non-optional) NSDictionary .

Here is a simpler example demonstrating the same problem with CFString vs NSString :

 let cfString = "foobar" as CFString? if let s1 = cfString as? NSString { print("s1 = \(s1)") // not executed } 

(The question remains why this does not give a compiler error or at least a compiler warning, because this optional cast may never work.)

But casting to an optional NSString? works:

 if let s2 = cfString as NSString? { print("s2 = \(s2)") // prints "s2 = foobar" } 

In your case, if you change the "problem case" to

 if let problemDictionary = cfDict as NSDictionary? { print(problemDictionary) } 

then the if block is executed.


Please note that your method for constructing CFDictionary in Swift is incorrect and actually caused program crashes in my test. One reason is that dictionary callbacks are set to empty structures. Another problem is that unsafeAddressOf(key) connects the Swift string to an NSString , which can be released immediately.

I don't know what is the best way to build CFDictionary in Swift, but this worked in my test:

 func optionalProblemDictionary() -> CFDictionary? { let key = "key" as NSString let value = "value" as NSString var keys = [ unsafeAddressOf(key) ] var values = [ unsafeAddressOf(value) ] var keyCallBacks = kCFTypeDictionaryKeyCallBacks var valueCallBacks = kCFTypeDictionaryValueCallBacks let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, &keys, &values, 1, &keyCallBacks, &valueCallBacks) return cfDictionary } 
+5
source

Source: https://habr.com/ru/post/1232020/


All Articles