CFDictionary не будет соединяться с NSDictionary (Swift 2.0 / iOS9)

Хорошо, это тот случай, с которым я столкнулся при работе с CGImageSource и заметил, что в некоторых случаях при бесплатном мостовом соединении между CFDictionary и NSDictionary возникают проблемы. Мне удалось построить приведенный ниже пример, чтобы показать, что я имею в виду:

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)

1 ответ

Решение

Кажется, причина в том, что функция возвращает необязательный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)
}

тогда блок if выполняется.


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

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

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
}
Другие вопросы по тегам