Как использовать 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