> On Sep 25, 2017, at 6:12 PM, Kenny Leung via swift-users
> <[email protected]> wrote:
>
> I’m trying to implement the AudioQueue example from Apple in Swift, and keep
> it as Swifty as I can. I’ve run into a problem where I have a let ivar for
> the AudioQueue, but the only way to initialize that let ivar is to pass a
> block to the function that creates the AudioQueue. I get the error, "Variable
> 'self.mQueue' used before being initialized”. Is there any way to get around
> this catch?
The compiler cannot guarantee that the code running inside your block does not
try to use mQueue before it is initialized. Swift strictly enforces its
initialization rules, so the compiler rejects your code.
One common solution is to change mQueue into an implicitly-unwrapped optional
var. The compiler still can't tell if your block object uses mQueue before it
is initialized, but if it does it will get a well-defined runtime error due to
the nil IUO. That well-defined error is sufficient to pacify the initialization
rules.
Another solution might be to divide your data into two different types. It
looks like the block object only needs to access self.audioBuffers and
self.source. You might be able to box those two fields into a separate class
type and have the block object capture a reference to that object only. Then
the initialization order is simple enough for the compiler to understand:
1. PDAudioPlayer.init() initializes a source+audioBuffers object.
2. PDAudioPlayer.init() calls AudioQueueNewOutputWithDispatchQueue(), passing
it a block that captures a reference to the fully-initialized
source+audioBuffers object.
3. PDAudioPlayer.init() uses the results of #1 and #2 to complete its own
initialization or return nil.
This adds an extra allocation and extra indirection to each PDAudioPlayer
object, but as long as you don't have millions of these things the performance
difference should be negligible.
> ———8<————8<————
> class PDAudioPlayer {
> static let kNumberBuffers :Int = 3 // 1
> //var mDataFormat:AudioStreamBasicDescription // 2
> let mQueue :AudioQueueRef // 3
> //var mBuffers :[AudioQueueBufferRef] // 4
> //var mAudioFile :AudioFileID? // 5
> var bufferByteSize :UInt32? // 6
> var mCurrentPacket :Int64? // 7
> var mNumPacketsToRead :UInt32? // 8
> var mPacketDescs :UnsafePointer<AudioStreamPacketDescription>? // 9
> var mIsRunning: Bool = false // 10
>
> let dispatchQueue :DispatchQueue
> let source :PDFileAudioSource
> var audioBuffers :[PDAudioBuffer]
>
> init?(source:PDFileAudioSource) {
> self.source = source
> self.dispatchQueue = DispatchQueue(label:"AudioPlayer", qos:.default,
> attributes:[], autoreleaseFrequency:.workItem, target:nil)
> self.audioBuffers = [PDAudioBuffer]()
>
> var tempAudioQueue :AudioQueueRef?
> var dataFormat = source.mDataFormat
> let status = AudioQueueNewOutputWithDispatchQueue(&tempAudioQueue,
> &dataFormat, 0, self.dispatchQueue) { [weak self] (queue, buffer) in //
> ERROR on this line
> guard let this = self else {
> return // block
> }
> guard let audioBuffer =
> this.audioBufferForAudioQueueBuffer(aqBuffer:buffer) else {
> return // block
> }
> this.source.fillBuffer(audioBuffer)
> }
> if status != 0 {
> return nil
> }
> guard let audioQueue = tempAudioQueue else {
> return nil
> }
> self.mQueue = audioQueue
> }
>
> private func audioBufferForAudioQueueBuffer(aqBuffer:AudioQueueBufferRef)
> -> PDAudioBuffer? {
> for buffer in self.audioBuffers {
> if buffer.audioQueueBuffer == aqBuffer {
> return buffer
> }
> }
> return nil
> }
> }
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users