Update the progress bar of function C
I am working on an iOS 8 audio app in Swift. The MIDI file is loaded and when the user clicks the Save button, it is displayed in the file in a C function that manually pulls the samples.
Now I would like to update the progress bar in the interface for this save action.
I added a property watcher to var in the ViewController and I passed a pointer to that var to the C function, hoping it would update it during the loop ... well, no. Even if the C function updates the var value inside the loop, this update is "fired" only once, at the end. Is there a way to update the progress bar?
Here's the code.
Thank!
In ViewController:
var outProgressBarValue:Float = 0.0 {
willSet {
dispatch_async(dispatch_get_main_queue(), {
println("New value received! -> \(newValue)")
self.progressBarOutlet.setProgress(newValue, animated: true)
})
}
}
@IBAction func saveButton(sender: AnyObject) {
[...]
let backgroundQueue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)
dispatch_async(backgroundQueue, {
WriteOutputFile(url, self.musicSequence!, Sound.sharedInstance.musicPlayer, self.processingGraph, &self.outProgressBarValue)
dispatch_async(dispatch_get_main_queue(), {
restoreOnlineRendering(processingGraph: self.processingGraph, mainMixerNode: self.mainMixerNode, ioNode: &(self.ioNode))
self.saveButtonOutlet.setTitle("Done", forState: UIControlState.Normal)
[...]
}
In the linked C file:
void WriteOutputFile(CFURLRef url, MusicSequence musicSequence, MusicPlayer musicPlayer, AUGraph processingGraph, float *outProgressBarValue) {
[…]
CheckError(MusicPlayerStart(musicPlayer), "MusicPlayerStart");
do {
CheckError(AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, bufferList), "AudioUnitRender");
tStamp.mSampleTime += (Float64)numFrames;
CheckError(ExtAudioFileWrite(outfile, numFrames, bufferList), "ExtAudioFileWrite");
CheckError(MusicPlayerGetTime (musicPlayer, ¤tTime), "MusicPlayerGetTime");
*outProgressBarValue = currentTime / sequenceLength;
printf("outProgressBarValue:\t %f\n", *outProgressBarValue);
} while (currentTime < sequenceLength);
CheckError(MusicPlayerStop(musicPlayer), "MusicPlayerStop");
[…]
}
source to share
If monitoring doesn't work, why not send the update explicitly to the controller? For example, via NSNotification.
Here's what I did as a proof of concept:
-
Add an Objective-C class file with .h and .m files. No need to define a class in this file, just put your c-function in .m and declaration in .h.
-
Set up the bridge header where you import the .h file. The bridge header is usually named "-Bridging-Header.h".
-
Now you can just call your function in any swift class.
-
In the .m file, use the c function to import "
<UIKit/UIkit.h>
" (or Foundation). -
If necessary, send a notification from your c function similar to this:
NSNotification *notif = [[NSNotification alloc] initWithName:@"Update" object:nil userInfo:@{@"progress" : @0.42}]; [[NSNotificationCenter defaultCenter] postNotification:notif];
-
In the swift file, follow the normal procedure to add
self
as an observer for the notification and call the update function with the values passed in the dictionaryuserInfo
.
source to share