5

Хорошо, это случай, который я натолкнулся на работу с CGImageSource и заметил, что беспошлинный мост между CFDictionary и NSDictionary, похоже, сталкивается с проблемами в некоторых случаях , Я сумел построить следующий пример, чтобы показать, что я имею в виду:CFDictionary не будет соединяться с NSDictionary (Swift 2.0/iOS9)

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 
} 

довольно проста (и немного глупо), но его функция, возвращающая и дополнительный CFDictionary. «Веселье» начинается при попытке создать NSDictionary из этой функции:

Почему не будет работать следующее:

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

В то время как это работает нормально?

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

XCode 7.0 (7A220)

ответ

5

Причина, кажется, что функция возвращает дополнительный CFDictionary? и что не может быть приведен к (не по желанию) NSDictionary.

Вот простой пример, демонстрирующий те же проблемы с CFString против NSString:

let cfString = "foobar" as CFString? 

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

(остается вопрос, почему это не дает ошибку компилятора или по крайней мере предупреждение компилятора, потому что это необязательное литая может не никогда успеха)

Но кастинг к дополнительным NSString? работам:.

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

В вашем случае, если вы измените «проблемное дело» в

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

то если-блок выполнен.


Обратите внимание, что ваш метод, чтобы построить в Swift в CFDictionary не является правильным и на самом деле вызвало сбой программы в моем тесте. Одна из причин заключается в том, что для обратных вызовов словаря установлены пустые структуры. Другая проблема заключается в том, что unsafeAddressOf(key) соединяет строку Swift с номером NSString, который может быть немедленно освобожден.

Я не знаю, что лучший способ заключается в создании в Swift, в CFDictionary, но это работает в моем тесте:

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 
} 
+0

Он не отвечает на вопрос - как преобразовать в NSDictionary. –

+0

@AlexanderVolkov: Я думаю, что он делает: 'if let problemDictionary = cfDict как NSDictionary? {...} 'отличает CFDictionary? в NSDictionary ?, и использует необязательную привязку, чтобы развернуть это в NSDictionary. Пожалуйста, дайте мне знать, какая именно информация отсутствует. –

+0

Взгляните на скриншот. Результат приведения - nil - http://www.screencast.com/t/hbjhDzCs0K –