iosswiftnsnotificationbatterylevelnotificationcenter

What is the correct syntax for NotificationCenter to return batteryLevel and batteryState in Swift 3.1


I'm a newbie to Swift (using Xcode 8.3.3, Swift 3.1) and I'm trying to display battery level and battery state and update them when the values change. Here's what I have so far:

import UIKit
class ViewController: UIViewController {

@IBOutlet weak var myBatteryPercent: UILabel!
@IBOutlet weak var myBatteryState: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    UIDevice.current.isBatteryMonitoringEnabled = true


    NotificationCenter.default.addObserver(self, selector: Selector(("batteryLevelDidChange:")),
     name: NSNotification.Name.UIDeviceBatteryLevelDidChange,
     object: nil)

    NotificationCenter.default.addObserver(self, selector: Selector(("batteryStateDidChange:")),
     name: NSNotification.Name.UIDeviceBatteryStateDidChange,
     object: nil)

    var batteryLevel: Float {
        return UIDevice.current.batteryLevel
    }

    var batteryState: UIDeviceBatteryState {
        return UIDevice.current.batteryState
    }

    switch batteryState {
    case .unplugged, .unknown:
        myBatteryState.text = "not charging"
    case .charging, .full:
        myBatteryState.text = "charging or full"
    }

    myBatteryPercent.text = "\(Int((batteryLevel) * 100))%"



    func batteryLevelDidChange (notification: Notification) {
        myBatteryPercent.text = "\(Int((batteryLevel) * 100))%"
    }
    func batteryStateDidChange (notification: Notification) {
        switch batteryState {
        case .unplugged, .unknown:
            myBatteryState.text = "not charging"
        case .charging, .full:
            myBatteryState.text = "charging or full"
        }
    }    
}

My app crashes when either the level or state changes generating this error message: [Battery_Display.ViewController batteryLevelDidChange:]: unrecognized selector sent to instance 0x100b0cf10'.

What am I doing wrong?


Solution

  • Basically you're wrong with a placement of the notification handlers. The handlers are declared inside viewDidLoad method and they are out of scope for NotificationCenter singleton. Just put them out of viewDidLoad and it should work:

    import UIKit
    class ViewController: UIViewController {
    
        @IBOutlet weak var myBatteryPercent: UILabel!
        @IBOutlet weak var myBatteryState: UILabel!
        var batteryLevel: Float {
            return UIDevice.current.batteryLevel
        }
    
        var batteryState: UIDeviceBatteryState {
            return UIDevice.current.batteryState
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            UIDevice.current.isBatteryMonitoringEnabled = true
    
    
            NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelDidChange), name: NSNotification.Name.UIDeviceBatteryLevelDidChange, object: nil)
    
            NotificationCenter.default.addObserver(self, selector: #selector(batteryStateDidChange), name: NSNotification.Name.UIDeviceBatteryStateDidChange, object: nil)
    
            switch batteryState {
            case .unplugged, .unknown:
                myBatteryState.text = "not charging"
            case .charging, .full:
                myBatteryState.text = "charging or full"
            }
    
            myBatteryPercent.text = "\(Int((batteryLevel) * 100))%"
    
        }
    
        func batteryLevelDidChange (notification: Notification) {
            myBatteryPercent.text = "\(Int((batteryLevel) * 100))%"
        }
    
        func batteryStateDidChange (notification: Notification) {
            switch batteryState {
            case .unplugged, .unknown:
                myBatteryState.text = "not charging"
            case .charging, .full:
                myBatteryState.text = "charging or full"
            }
        }
    }