0

I am new in Swift and I tried to find out a solution without success to this issue.

I have in ViewDidLoad() :

    AudioContext.load(fromAudioURL: self.url) { audioContext in

        guard let audioContext = audioContext else {
            fatalError("Couldn't create the audioContext")
        }
        
        self.outputArray = self.render(audioContext: audioContext, targetSamples: 300)
        samples = self.outputArray.map { -Int($0) }
        print("TOTAL1:\(samples)") **// IT WORKS OK**
        
    }
    print("TOTAL2:\(samples)") // IT DOES NOT WORK => Give nothing

and the Function with completion handler:

public static func load(fromAudioURL audioURL: URL, completionHandler: @escaping (_ audioContext: AudioContext?) -> ())  {
    let asset = AVURLAsset(url: audioURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: NSNumber(value: true as Bool)])
    
    guard let assetTrack = asset.tracks(withMediaType: AVMediaType.audio).first else {
        fatalError("Couldn't load AVAssetTrack")
    }
    
    asset.loadValuesAsynchronously(forKeys: ["duration"]) {
        var error: NSError?
        let status = asset.statusOfValue(forKey: "duration", error: &error)
        switch status {
        case .loaded:
            guard
                let formatDescriptions = assetTrack.formatDescriptions as? [CMAudioFormatDescription],
                let audioFormatDesc = formatDescriptions.first,
                let asbd = CMAudioFormatDescriptionGetStreamBasicDescription(audioFormatDesc)
                else { break }
            
            let totalSamples = Int((asbd.pointee.mSampleRate) * Float64(asset.duration.value) / Float64(asset.duration.timescale))
            let audioContext = AudioContext(audioURL: audioURL, totalSamples: totalSamples, asset: asset, assetTrack: assetTrack)
        
            completionHandler(audioContext)
            
            
            return 
            
        case .failed, .cancelled, .loading, .unknown:
            print("Couldn't load asset: \(error?.localizedDescription ?? "Unknown error")")

        @unknown default:
            print("Couldn't load asset: \(error?.localizedDescription ?? "Unknown error")")

        }
      
        
        completionHandler(nil)
    }
}

What should i do make sure I have Print TOTAL2 with the same result as TOTAL1. I need in fact to use the array SAmple outside the closure and I don't understand how to do it.

Many many many thanks if you could help me :-) Cheers

  • You can't do anything with the data until the closure has been called but what solution is right for you is hard to say without knowing how you are going to use it. There are some suggestions in [this question](https://stackoverflow.com/questions/38364288/getting-data-out-of-a-closure-that-retrieves-data-from-firebase) – Joakim Danielson Sep 06 '20 at 19:05
  • 1
    Many thanks Joakim. I was able to fix the issue thanks to you and I found also a useful link : https://www.appcoda.com/swift-delegate/ – stephaneP Sep 09 '20 at 07:42

1 Answers1

0

This escaping closure will execute sometime in future and not definitely after print("TOTAL2:\(samples)"). One of the solutions will be to save samples as a view property and store it from the closure, where you are printing print("TOTAL1:\(samples)"). And then you can use it later. But the question will be how to know whether closure was called and samples has latest data.

Or even better you can call a function which needs samples from within the first closure. Ensure to use weak self.

Pankaj Kulkarni
  • 553
  • 4
  • 12