3

I have a question related to my code:

func isNotificationsEnabled()->Bool{
    var isNotificationEnabled = false
    center.getNotificationSettings() { (settings) in
        switch settings.soundSetting{
        case .enabled:
            isNotificationEnabled = true
           break
        case .disabled:
             isNotificationEnabled = false
             break

        case .notSupported:
            isNotificationEnabled = false
             break
        }
    }

     return isNotificationEnabled
}

This function return result before center.getNotificationSettings() returns results. Is there any way to wait for result of center.getNotificationSettings() and sync this function?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Dawid Macura
  • 193
  • 1
  • 9
  • 1
    Possible duplicate of [Returning data from async call in Swift function](http://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – Sasha Kozachuk Nov 30 '16 at 12:13
  • 1
    Don't ask, tell! Use an asynchronous completion handler. – vadian Nov 30 '16 at 12:13

4 Answers4

4

What you are looking for is called Completion block in iOS, Try this,

func isNotificationsEnabled(completion:@escaping (Bool)->Swift.Void){
        var isNotificationEnabled = false
        center.getNotificationSettings() { (settings) in
            switch settings.soundSetting{
            case .enabled:
                isNotificationEnabled = true
                completion(isNotificationEnabled)
                break
            case .disabled:
                isNotificationEnabled = false
                completion(isNotificationEnabled)
                break

            case .notSupported:
                isNotificationEnabled = false
                completion(isNotificationEnabled)
                break
            }
        }
    }

Usage,

isNotificationsEnabled { (isNotificationEnabled) in
    debugPrint(isNotificationEnabled)           
}
Mohammad Zaid Pathan
  • 16,304
  • 7
  • 99
  • 130
3

This is an example using a completion block, it's reduced but has the same functionality as your code:

func isNotificationsEnabled(completion:@escaping (Bool)->() ) {
    center.getNotificationSettings() { (settings) in
        switch settings.soundSetting {
        case .enabled:
            completion(true)
            
        default:
            completion(false)
        }
    }
}

which can be still more reduced to the essential:

func isNotificationsEnabled(completion:@escaping (Bool)->() ) {
    center.getNotificationSettings() { (settings) in
        completion (settings.soundSetting == .enabled)
    }
}

Since only the .enabled case returns true use default to return false in all other cases. By the way: In Swift break statements are not needed.

And call it:

isNotificationsEnabled { success in
    if success {
        print("is enabled")
    } else {
        print("is disabled")
    }
}

In Swift 5.5 and higher you can take advantage of async/await

func isNotificationsEnabled() async -> Bool {
    let settings = await center.notificationSettings()
    switch settings.soundSetting {
        case .enabled:
            return true
        case .disabled, .notSupported:
            return false    
    }
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • The Swift 5.5 example does not seem to be correct. I keep getting a `Missing argument for parameter 'completionHandler' in call` error – Bartender1382 Nov 22 '22 at 02:55
  • 1
    Please note the difference between `getNotificationSettings()` with completion handler and `notificationSettings()` without. See the [documentation](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649524-getnotificationsettings). – vadian Nov 22 '22 at 05:35
0

FYI, you can probably simplify this even further:

func isNotificationsEnabled(completionHandler: @escaping (Bool) -> Void) {
    center.getNotificationSettings { settings in
        completionHandler(settings.soundSetting == .enabled)
    }
}

And as others pointed out, it then is invoked as:

isNotificationsEnabled { enabled in
    if enabled {
        print("is enabled")
    } else {
        print("is not enabled")
    }
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
-1

Add a completion handler!

func isNotificationsEnabled(completion: (Bool) -> ())->Bool{
    var isNotificationEnabled = false
    center.getNotificationSettings() { (settings) in
        switch settings.soundSetting{
        case .enabled:
            isNotificationEnabled = true
           break
        case .disabled:
             isNotificationEnabled = false
             break

        case .notSupported:
            isNotificationEnabled = false
             break
        }
    }

     return isNotificationEnabled
     completion(isNotificationEnabled)
}

And then call it

isNotificationEnabled() { isNotificationsEnabled in
   print(isNotificationsEnabled)
}
Alec.
  • 5,371
  • 5
  • 34
  • 69
  • 1
    No, you are calling `completion` _after_ your `return` statement (i.e., you'll never get there). You should (a) change the method definition to no longer return anything (given that you now have the completion handler); and (b) remove the `return` statement. – Rob Nov 30 '16 at 13:04