Hi Greg.

Thanks for the insight. In this case, I think I’m saved because I don’t 
actually need to capture self in the block. I guess I was just too far along on 
my train to realize that. I think this will work and it will keep the code 
simple and neat.

I guess we'll see as I complete this project whether I really have everything I 
need for the callback block. I may have to resort to one of the other measures 
you all have suggested.

Thanks again!

-Kenny


> On Sep 26, 2017, at 12:40 AM, Greg Parker <gpar...@apple.com> wrote:
> 
>> 
>> On Sep 25, 2017, at 6:12 PM, Kenny Leung via swift-users 
>> <swift-users@swift.org <mailto:swift-users@swift.org>> 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
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to