KML KML - 28 days ago 10
Swift Question

Returning bool in nested function

I want to request some permissions and want to return false unless all permissions have been granted.
I get an error:
"Unexpected non-void return value in void function"

But I am returning true/false in all circumstances, what is wrong ?

func requestPermissions () -> Bool {
let types: UIRemoteNotificationType = [.alert, .badge, .sound]
UIApplication.shared.registerForRemoteNotifications(matching: types)
let center = UNUserNotificationCenter.current()

AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
if (videoGranted) {
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
if (audioGranted) {
center.requestAuthorization(options: [.alert, .badge, .sound]) { (notificationGranted:Bool, error) -> Void in
if (notificationGranted) {
DispatchQueue.main.async {

return true
print("Video, audio & notifications granted")
}
} else {

return false
print("Rejected notifications")
}
}
}else {

return false
print("Rejected audio")
}
})
} else {

return false
print("Rejected video")
}
})
}


Any help would be very much appreciated ! Thank you.


Alternative Answer:


func requestPermissionss (completion: ((Bool, Bool, Bool)->Void)?) {
let types: UIRemoteNotificationType = [.alert, .badge, .sound]
UIApplication.shared.registerForRemoteNotifications(matching: types)
let center = UNUserNotificationCenter.current()

AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
center.requestAuthorization(options: [.alert, .badge, .sound]) { (notificationGranted:Bool, error) -> Void in
completion?(videoGranted, audioGranted, notificationGranted)
}
})
})
}

Answer

The issue is that inside the closure return keyword has nothing to do with the return of requestPermissions() function. It rather means return from the closure, which doesn't actually return anything (because of the -> Void part)

You can pass a closure with three bool parameters to your function like this:

func requestPermissions (completion: ((Bool, Bool, Bool)->Void)?) {
    let types: UIRemoteNotificationType = [.alert, .badge, .sound]
    UIApplication.shared.registerForRemoteNotifications(matching: types)
    let center = UNUserNotificationCenter.current()

    AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
        if (videoGranted) {
            AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
                if (audioGranted) {
                    center.requestAuthorization(options: [.alert, .badge, .sound]) { (notificationGranted:Bool, error) -> Void in
                        if (notificationGranted) {
                            completion?(true, true, true)
                        } else {
                            completion?(true, true, false)
                        }
                    }
                }else {
                    completion?(true, false, false)
                }
            })
        } else {
            completion?(false, false, false)
        }
    })
}

Usage:

requestPermissions { (videoGranted, audioGranted, notificationsGranted) in
    print("video granted: \(videoGranted)")
    print("audio granted: \(audioGranted)")
    print("notifications granted: \(notificationsGranted)")
}

Note, that I also removed DispatchQueue.main.async because it has no sense here. Again, return means return from the current scope, not from the outer function.

P.S. Another thing to note is that with your code you won't ask permissions for audio and notifications if permission for video was declined. Not sure if it is intentional or not.