Swift и AudioFormatGetProperty (_: _: _: _: _ :) - PullRequest
0 голосов
/ 20 мая 2018

Я хочу знать, как управлять неуправляемым CFType AudioFormatGetProperty () с помощью swift.

Эта функция является низкоуровневым API, и некоторые kAudioFormatProperty_XXX возвращают объект CFType без аннотации.Согласно Документации, в нем говорится:

. Вызывающая сторона отвечает за освобождение возвращаемой строки.

Вызывающий должен вызывать функцию CFRelease для возвращаемого словаря.

kAudioFormatProperty_FormatName
kAudioFormatProperty_ChannelLayoutName
kAudioFormatProperty_ChannelLayoutSimpleName
kAudioFormatProperty_ChannelName
kAudioFormatProperty_ChannelShortName
kAudioFormatProperty_ID3TagToDictionary

Swift не поддерживает CFRelease, поэтому я думаю, что в этом случае вызывающая сторона должна сделать что-то вроде CFRelease.Не могли бы вы дать какой-нибудь совет?

Мой фрагмент кода следующий:

var aclSize : Int = 0
let aclPtr : UnsafePointer<AudioChannelLayout>? =
    CMAudioFormatDescriptionGetChannelLayout(desc, &aclSize)

var nameSize : UInt32 = 0
let err1 : OSStatus =
    AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutName,
                               UInt32(aclSize), aclPtr, &nameSize)

let count : Int = Int(nameSize) / MemoryLayout<CFString>.size
let ptr : UnsafeMutablePointer<CFString> =
    UnsafeMutablePointer<CFString>.allocate(capacity: count)

let err2 : OSStatus =
    AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutName,
                           UInt32(aclSize), aclPtr, &nameSize, ptr)

// do something here

ptr.deallocate() // Is this same as CFRelease(cfstringref)?

1 Ответ

0 голосов
/ 20 мая 2018

Я нашел лучшее решение для AudioFormatGetProperty ().

Простое решение:

kAudioFormatProperty_ * подобно FormatName или ChannelLayoutName возвращают одно значение CFString.

В этом случае я могу использовать следующие с поддержкой ARC.Не нужно выпускать вручную.

//
var formatSize : UInt32 = UInt32(MemoryLayout<CFString>.size)
var format : CFString!
let err : OSStatus =
    AudioFormatGetProperty(kAudioFormatProperty_FormatName,
                           asbdSize, asbdPtr, &formatSize,
                           &format)
formatString = String(format as NSString)

//
var nameSize : UInt32 = UInt32(MemoryLayout<CFString>.size)
var name : CFString!
let err : OSStatus =
    AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutName,
                           UInt32(aclSize), aclPtr,
                           &nameSize, &name)
layoutString = String(name as NSString)

ПРИМЕЧАНИЕ:

Как определить, действительно ли "необозначенный объект CFType неуправляем или нет".

Ниже приведены дешевые процедуры отладки, которые я делал в этом вопросе.Я считаю, что это плохое ноу-хау, поэтому я хотел бы узнать более лучший способ.

1) Поставьте некоторую проверку для RetainCount CFType.

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

let ptr : UnsafeMutablePointer<CFString> = ...
CFShow(ptr.pointee) // to confirm it is live
Swift.print(CFGetRetainCount(ptr.pointee)) // to check retainCount

2) Если это небольшое значение, такое как 2 или 3, то попробуйте автоматически выпустить его как:

let unmanaged = Unmanaged<CFString>.passUnretained(ptr.pointee)
_ = unmanaged.autorelease()

3) Еслион немедленно падает (в пределах runloop), управляется (может или не может быть ARC)

4) Если он работает как есть, я предполагаю, что он не управляется (поэтому autorelase обрабатывает retainCount)


Обновление:

Это еще один тест на игровой площадке.

После показа RetainCount изменен с 3 на 2.

import UIKit
import AVFoundation

let avacl : AVAudioChannelLayout? =
    AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_AAC_5_1)
var unmanaged : Unmanaged<CFString>? = nil
do {
    let aclPtr : UnsafePointer<AudioChannelLayout> = avacl!.layout
    var aclSize : Int = MemoryLayout<AudioChannelLayout>.size +
        (Int(aclPtr.pointee.mNumberChannelDescriptions) - 1) *
        (MemoryLayout<AudioChannelDescription>.size)
    var nameSize : UInt32 = UInt32(MemoryLayout<CFString>.size)

    let ptr = UnsafeMutablePointer<CFString>.allocate(capacity: 1)
    defer { ptr.deallocate() }
    _ = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutName,
                               UInt32(aclSize), aclPtr, &nameSize, ptr)
    _ = ptr.move() // make CFString managed

    unmanaged = Unmanaged<CFString>.passUnretained(ptr.pointee)
    CFGetRetainCount(unmanaged?.takeUnretainedValue())
}
CFGetRetainCount(unmanaged?.takeUnretainedValue())

На следующем рисунке RetainCount изменен с 4 на 2. (2 опущены, когда выходят за рамки)

import UIKit
import AVFoundation

let avacl : AVAudioChannelLayout? =
    AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_AAC_5_1)
var unmanaged : Unmanaged<CFString>? = nil
do {
    let aclPtr : UnsafePointer<AudioChannelLayout> = avacl!.layout
    var aclSize : Int = MemoryLayout<AudioChannelLayout>.size +
        (Int(aclPtr.pointee.mNumberChannelDescriptions) - 1) *
        (MemoryLayout<AudioChannelDescription>.size)
    var nameSize : UInt32 = UInt32(MemoryLayout<CFString>.size)

    var name : CFString!
    _ = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutName,
                           UInt32(aclSize), aclPtr, &nameSize, &name)

    unmanaged = Unmanaged<CFString>.passUnretained(name!)
    CFGetRetainCount(unmanaged?.takeUnretainedValue())
}
CFGetRetainCount(unmanaged?.takeUnretainedValue())
...