Swift vs Objective C проблема манипулирования указателем - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть этот код в Objective C, который отлично работает:

list = controller->audioBufferList;
list->mBuffers[0].mDataByteSize = inNumberFrames*kSampleWordSize;
list->mBuffers[1].mDataByteSize = inNumberFrames*kSampleWordSize;

И он работает фантастически, он обновляет поле mDataByteSize mBuffers [0] & mBuffers [1].Я пытался перевести то же самое в Swift, но он не работает:

public var audioBufferList:UnsafeMutableAudioBufferListPointer

В функции

let listPtr = controller.audioBufferList.unsafeMutablePointer

let buffers = UnsafeBufferPointer<AudioBuffer>(start: &listPtr.pointee.mBuffers, count: Int(listPtr.pointee.mNumberBuffers))

for var buf in buffers {
    buf.mDataByteSize = inNumberFrames * UInt32(sampleWordSize)
    NSLog("Data byte size \(buf.mDataByteSize)")
}

for buf in buffers {
    NSLog("Data byte size \(buf.mDataByteSize)")
}

mDataByteSize не обновляется.NSLog при чтении за секунду для цикла указывает на исходные значения, а не на обновленные.Кажется, что var buf ссылается на другой buf, делая копию.Как мне это исправить?Это проблема чисто языка Swift, которую я не могу понять.

РЕДАКТИРОВАТЬ: Как указал Мартин, я исправил проблему, изменив цикл for следующим образом:

 for i in 0..<Int(listPtr.pointee.mNumberBuffers) {
    buffers[i].mDataByteSize = inNumberFrames * UInt32(sampleWordSize)
}

Теперь это работает,Но это еще больше пробудило моё любопытство в Swift Language, насколько он не интуитивен и насколько раздражает разработчиков, которые используют указатели для манипулирования вещами.Почему следующие циклы не работают?Копируются ли буферы var по значению?

     for buf in buffers {
         var buffer = buf
         buffer.mDataByteSize = inNumberFrames * UInt32(sampleWordSize)
     }

Или

    for var buf in buffers {
        buf.mDataByteSize = inNumberFrames * UInt32(sampleWordSize)
    }

РЕДАКТИРОВАТЬ 2: Ответ Хэмиша ставит под сомнение обоснованность использования listPtr в любом месте.Я использовал listPtr в ряде вызовов, таких как:

let status = AudioUnitRender(controller.audioUnit!, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, listPtr)

Теперь мне нужно знать, где мы можем использовать listPtr, а где нет!

1 Ответ

0 голосов
/ 28 ноября 2018

Для вызова:

let buffers = UnsafeBufferPointer<AudioBuffer>(start: &listPtr.pointee.mBuffers, count: Int(listPtr.pointee.mNumberBuffers))

&listPtr.pointee.mBuffers создает временный указатель, действительный только на время вызова инициализатора UnsafeBufferPointer.Поэтому попытка использовать указатель буфера приводит к неопределенному поведению (мы надеемся, что компилятор предупредит о таких случаях в Swift 5.1).

Вместо этого вы можете выполнить итерацию напрямуюUnsafeMutableAudioBufferListPointer, в соответствии с MutableCollection.

Например:

for index in audioBufferList.indices {
  audioBufferList[index].mDataByteSize = inNumberFrames * UInt32(sampleWordSize)
  print("Data byte size \(audioBufferList[index].mDataByteSize)")
}

for buffer in audioBufferList {
  print("Data byte size \(buffer.mDataByteSize)")
}
...