2015-09-22 22 views
5

OK, questo è un caso che ho riscontrato lavorando con CGImageSource e ho notato che il collegamento senza pedaggio tra CFDictionary e NSDictionary sembra incorrere in problemi in alcuni casi . Sono riuscito a costruire l'esempio di seguito per mostrare quello che voglio dire:CFDictionary non collegherà 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 
} 

abbastanza semplice (e un po 'stupido), ma la sua una funzione che restituisce e facoltativo CFDictionary. Il "divertimento" inizia quando si tenta di creare un NSDictionary da questa funzione:

Perché i seguenti lavori non funzioneranno?

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

Mentre funziona?

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

XCode 7.0 (7A220)

risposta

5

Il motivo sembra essere che la funzione restituisce un opzionale CFDictionary? e che non può essere gettato a un (non opzionale) NSDictionary.

Ecco un esempio più semplice che dimostra lo stesso problema con CFString vs NSString:

let cfString = "foobar" as CFString? 

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

(La domanda rimane perché questo non dà un errore di compilazione o almeno un avviso del compilatore, perché questo cast opzionale può mai successo)

Ma un casting per un optional NSString? opere:.

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

Nel tuo caso, se si modifica il "caso problematico" per

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

poi il blocco se-viene eseguito.


Si noti che il metodo per costruire una CFDictionary a Swift non è corretto e in realtà causata programma va in crash nel mio test. Una ragione è che i callback del dizionario sono impostati su strutture vuote. Un altro problema è che lo unsafeAddressOf(key) collega la stringa Swift a uno NSString che può essere deallocato immediatamente.

Non so che cosa il metodo migliore è quello di costruire un CFDictionary a Swift, ma questo ha funzionato nel mio 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 
} 
+0

Essa non risponde alla domanda - come convertire a NSDictionary. –

+0

@AlexanderVolkov: Penso che lo faccia: 'se let problemDictionary = cfDict come NSDictionary? {...} 'lancia il CFDictionary? a NSDictionary ?, e utilizza l'associazione facoltativa per scartarla a NSDictionary. Per favore fammi sapere quali informazioni ti mancano. –

+0

Dai uno sguardo allo screenshot. Il risultato del cast è nil - http://www.screencast.com/t/hbjhDzCs0K –