Ben Botvinick
Ben Botvinick

Reputation: 3285

Recursion in async callback (Swift)

Here's some code that it intended to make the phone vibrate (async), await the completion of this task, and then make it vibrate again immediately after:

func vibrate() {
    AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
    AudioServicesAddSystemSoundCompletion(SystemSoundID(kSystemSoundID_Vibrate), nil, nil, { (soundId, clientData) -> Void in
        self.vibrate()
    }, nil)
}

Xcode gives the following error:

A C function pointer cannot be formed from a closure that captures context

How I can recurse from inside of this async function?

Upvotes: 2

Views: 853

Answers (3)

Ben Botvinick
Ben Botvinick

Reputation: 3285

Here's the solution I eventually found. Turns out, there is a built-in function, AudioServicesPlaySystemSoundWithCompletion, that takes a callback as an argument:

func vibrate() {
    AudioServicesPlaySystemSoundWithCompletion(SystemSoundID(kSystemSoundID_Vibrate)) {
        self.vibrate()
    }
}

Upvotes: 0

M Abubaker Majeed
M Abubaker Majeed

Reputation: 1003

You can also use this way to call any function within class;

AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) 
let myData = unsafeBitCast(self, to: UnsafeMutableRawPointer.self) 
AudioServicesAddSystemSoundCompletion(SystemSoundID(kSystemSoundID_Vibrate), 
CFRunLoopGetMain(), nil ,{ (soundId, clientData) in 
let currentSelf = unsafeBitCast(clientData, to: YOUR_CLASS_NAME.self) 
currentSelf.vibrate() // call any funcation from current Controller
}, myData)

Upvotes: 0

Glenn Posadas
Glenn Posadas

Reputation: 13283

I was trying hard to find a solution to your question, and I stumbled upon this thread: https://forums.swift.org/t/a-c-function-pointer-cannot-be-formed-from-a-local-function-that-captures-context-on-swift-package/9388/6

I did encapsulate the vibrate() method into a new struct, like so:

import AudioToolbox
import CoreAudioKit

struct Vibrator {
    static func vibrate() {
        AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
        AudioServicesAddSystemSoundCompletion(SystemSoundID(kSystemSoundID_Vibrate), nil, nil, { (soundId, clientData) in
            Vibrator.vibrate()
        }, nil)
    }
}

and call it of course like so: Vibrator.vibrate(). Voila!

I hope this helps!

Upvotes: 1

Related Questions