2

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?

Ben Botvinick
  • 2,837
  • 3
  • 16
  • 41
  • Compare https://stackoverflow.com/questions/33260808/how-to-use-instance-method-as-callback-for-function-which-takes-only-func-or-lit/33262376#33262376 – Martin R Oct 16 '18 at 04:54

3 Answers3

1

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!

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
  • You can also use this way to call any function within class, (i tried to convert code part separate, until now no success.) ` 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: SelectGenreViewController.self) currentSelf.vibrate() }, myData)` – M Abubaker Majeed Oct 16 '18 at 04:28
  • Interesting. Post that as an answer for people to see the code formatted properly. – Glenn Posadas Oct 16 '18 at 04:39
0

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)
0

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()
    }
}
Ben Botvinick
  • 2,837
  • 3
  • 16
  • 41