Как использовать CFDictionarySetValue в Swift?

В настоящее время я конвертирую код аппаратного декодирования Obj-C в версию Swift. (Xcode 8, Swift 3).

Я не знаю, как настроить словарь для настройки вывода на экране, также я не знаю, как его использовать.

Следующий код прекрасно работает в проекте Obj-C:

// set some values of the sample buffer's attachments
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);

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

// i got run-time error
let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer!, true)
let dict = unsafeBitCast(attachments, to: CFMutableDictionary.self)
CFDictionarySetValue(dict, unsafeBitCast(kCMSampleAttachmentKey_DisplayImmediately, to: UnsafeRawPointer.self), unsafeBitCast(kCFBooleanTrue, to: UnsafeRawPointer.self))

Это неправильно конвертировать CFString в UnsafeRawPointer? или это неправильно использовать CFDictionarySetValue метод?

это мой журнал ошибок.

2016-11-24 16:50:44.458 MyApp[35288:3519253] -[__NSSingleObjectArrayI __setObject:forKey:]: unrecognized selector sent to instance 0x6000002045a0
2016-11-24 16:50:44.466 MyApp[35288:3519253] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI __setObject:forKey:]: unrecognized selector sent to instance 0x6000002045a0'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010b02734b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010a0e421e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010b096f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x000000010afacc15 ___forwarding___ + 1013
    4   CoreFoundation                      0x000000010afac798 _CF_forwarding_prep_0 + 120
    5   MyApp                             0x000000010937ac7a _TFC14MyApp16ViewerController21receivedRawVideoFramefT5frameGSaVs5UInt8_4withVs5Int32_T_ + 4890
    6   MyApp                             0x000000010937d8e2 _TFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 4242
    7   MyApp                             0x000000010937daed _TToFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 61
    8   MyApp                            0x000000010937dd56 _TTDFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 70
    9   MyApp                             0x000000010937dcfe _TTWC14MyApp16ViewerControllerS_18IJCallbackProtocolS_FS1_12MainCallBackfTVs5Int3212callbackCodeS2_8argumentGSqSv_7argSizeS2__T_ + 62
    10  MyApp                             0x00000001093b22b2 _TFC14MyApp11AppDelegate19MainCallBack_StreamfTVs5Int32S1_GSqSv_S1__T_ + 258
    11  MyApp                             0x00000001093d26d3 _TFZFC14MyApp19IJStreamCoreWrapper6AttachFTSv2ipSS4portSi_T_U_FTVs5Int32S1_GSqSv_S1_GSqSv__T_ + 355
    12  MyApp                             0x00000001093d2719 _TToFZFC14MyApp19IJStreamCoreWrapper6AttachFTSv2ipSS4portSi_T_U_FTVs5Int32S1_GSqSv_S1_GSqSv__T_ + 9
    13  MyApp                             0x00000001093ee176 _ZL8CallbackPN14CStreamManager9Session_TEiPvi + 70
    14  MyApp                             0x00000001093f09d3 _Z25StreamManagerThread_VideoPv + 3155
    15  libsystem_pthread.dylib             0x000000010e494aab _pthread_body + 180
    16  libsystem_pthread.dylib             0x000000010e4949f7 _pthread_body + 0
    17  libsystem_pthread.dylib             0x000000010e494221 thread_start + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

2 ответа

Решение

В первом фрагменте кода у вас есть вызов CFArrayGetValueAtIndex, который возвращает словарь, который вы передаете CFDictionarySetValue,

Во втором фрагменте кода вы не звоните CFArrayGetValueAtIndex, Вы просто передаете массив CFDictionarySetValue, Поскольку массив не является словарем, вы получаете фатальную ошибку.

Мне удалось заставить это работать только со следующим:

let attachments = CMSampleBufferGetSampleAttachmentsArray(buf!, createIfNecessary: true)
let dict = unsafeBitCast(CFArrayGetValueAtIndex(attachments, 0), to: CFMutableDictionary.self)
CFDictionarySetValue(dict,
                     unsafeBitCast(kCMSampleAttachmentKey_DisplayImmediately, to: UnsafeRawPointer.self),
                     unsafeBitCast(kCFBooleanTrue, to: UnsafeRawPointer.self))

Я попробовал предложение @Alexander, и, хотя оно компилируется и выполняется, базовый CFDictionary не изменяется, и желаемый результат не достигается.

//  let attachments = CMSampleBufferGetSampleAttachmentsArray(buf!, createIfNecessary: true) as! Array<Dictionary<String, Any>>
//  var dict = attachments[0]
//  dict[kCMSampleAttachmentKey_DisplayImmediately as String] = true

Когда вы конвертируете код в Swift, гораздо лучше понять семантику программы и переписать соответствующий код Swift. Не пытайтесь просто конвертировать синтаксис по крупицам.

CMSampleBufferGetSampleAttachmentsArray возвращает вам ссылку на CFArray из CFDictionary экземпляров. Кастинг это CFArrayRef в CFMutableDictionaryRef имеет эффект просто сделать ссылку на первый экземпляр.

Лучше всего использовать нативные типы Swift. Я не могу предоставить точную реализацию, потому что я не уверен в типах в игре, но вот начало

//TODO: give me a better name
let array = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer!, true) as [[String: Bool]] //TODO:

//TODO: give me a better name
var firstDict = array[0]

firstDict[kCMSampleAttachmentKey_DisplayImmediately as String] = true
Другие вопросы по тегам