Swift 3 Xcode: How to display battery levels as an integer? - ios

I am making an app to read battery percentage using Swift!
Right now my out is something like this:
61.0% or 24.0% or 89.0%
What I'm trying to fix is getting rid of the .0 so it's an Int.
This is my code so far:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var infoLabel: UILabel!
var batteryLevel: Float {
return UIDevice.current.batteryLevel
}
var timer = Timer()
func scheduledTimerWithTimeInterval(){
timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(self.someFunction), userInfo: nil, repeats: true)
}
func someFunction() {
self.infoLabel.text = "\(batteryLevel * 100)%"
}
override func viewDidLoad() {
super.viewDidLoad()
UIDevice.current.isBatteryMonitoringEnabled = true
someFunction()
scheduledTimerWithTimeInterval()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I have tried something like this:
var realBatteryLevel = Int(batteryLevel)
However, I get this error
I have tried other method but none with any luck. Please, any solutions would be awesome! Thanks in advance!
EDIT
I was considering making the float batteryLevel into a String and then replacing ".0" with "" and I have seen this somewhere, however, I'm not sure how!

Try this instead:
func someFunction() {
self.infoLabel.text = String(format: "%.0f%%", batteryLevel * 100)
}
For future reference, all string format specifiers are listed here.

You just need to convert It inside your function :
func someFunction() {
self.infoLabel.text = "\(Int(batteryLevel * 100))%" }

Alternately, you could create an Int computed property for batteryLevel:
var batteryLevel: Int {
return Int(round(UIDevice.current.batteryLevel * 100))
}
Note that you might not be able to get the battery level. You should test for that and display a different string:
if UIDevice.current.batteryState == .unknown {
self.batteryLevelLabel.text = "n/a"
} else {
self.batteryLevelLabel.text = "\(self.batteryLevel)%"
}
Also note that rather than running a timer to fetch the battery level, you should subscribe to the .UIDeviceBatteryLevelDidChange notification. The "meat" of a view controller that handles all of this might look as follows:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var batteryLevelLabel: UILabel!
///Holds the notification handler for battery notifications.
var batteryNotificationHandler: Any?
///A computed property that returns the battery level as an int, using rounding.
var batteryLevel: Int {
return Int(round(UIDevice.current.batteryLevel * 100))
}
///A function to display the current battery level to a label,
////or the string "n/a" if the battery level can't be determined.
func showBatteryLevel() {
if UIDevice.current.batteryState == .unknown {
self.batteryLevelLabel.text = "n/a"
} else {
self.batteryLevelLabel.text = "\(self.batteryLevel)%"
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
///If we have a battery level observer, remove it since we're about to disappear
if let observer = batteryNotificationHandler {
NotificationCenter.default.removeObserver(observer: observer)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
showBatteryLevel() //display the battery level once as soon as we appear
//Create a notifiation handler for .UIDeviceBatteryLevelDidChange
//notifications that calls showBatteryLevel()
batteryNotificationHandler =
NotificationCenter.default.addObserver(forName: .UIDeviceBatteryLevelDidChange,
object: nil,
queue: nil, using: {
(Notification) in
self.showBatteryLevel()
})
}
override func viewDidLoad() {
super.viewDidLoad()
//Tell UIDevice that we want battery level notifications
UIDevice.current.isBatteryMonitoringEnabled = true
}
}

Related

ios Swift Protocol Data

I don't use storyboards.
I want to send protocol data using #objc button action.
However, the sent view controller does not run the protocol function.
May I know what the reason is?
In fact, there's a lot more code.
Others work, but only protocol functions are not executed.
The didUpdataChampion function is
Data imported into a different protocol.
I have confirmed that there is no problem with this.
protocol MyProtocolData {
func protocolData(dataSent: String)
func protocolCount(dataInt: Int)
}
class PickViewController: UIViewController,ChampionManagerDelegate{
static let identifier = "PickViewController"
var count = 0
var urlArray = [URL]()
var pickDelegate : MyProtocolData?
override func viewDidLoad() {
super.viewDidLoad()
champions.riot(url: "myURL")
}
#objc func topHand(){
pickDelegate?.protocolData(dataSent: "top")
print(count)
pickDelegate?.protocoCount(dataInt: count)
let cham = ChampViewController()
cham.modalPresentationStyle = .fullScreen
present(cham, animated: true, completion: nil)
}
//Data imported to another protocol
func didUpdataChampion(_ championManager: ChampionManager, champion: [ChampionRiot]) {
print(#function)
count = champion.count
for data in champion {
let id = data.id
guard let url = URL(string: "https://ddragon.leagueoflegends.com/cdn/11.16.1/img/champion/\(id).png") else { return }
urlArray.append(url)
count = urlArray.count
}
}
func didFailWithError(error: Error) {
print(error)
}
}
class ChampViewController: UIViewController,MyProtocolData {
var pickData = ""
var arrayCount = 0
override func viewDidLoad() {
super.viewDidLoad()
}
func protocolData(dataSent: String) {
print(#function)
pickData = dataSent
print(pickData)
}
func protocoCount(dataInt: Int) {
print(#function)
arrayCount = dataInt
print(arrayCount)
}
}
i don't see full code, for instance how you call bind to topHand(), my advice is:
check that topHand - is called
check that pickDelegate isn't nil inside topHand
Create Object fo your PickViewController class and set its delegate to self.
var yourObj = PickViewController()
override func viewDidLoad() {
super.viewDidLoad()
yourObj.delegate = self
}

Elapsed Timer not starting

I am building an elapsed timer and while the code gives no errors the timer does not start.
I am using two ViewControllers, one called Stopwatch which has the start stop function in it under the class Stopwatch() and then a regular ViewController with the rest in it.
View Controller Code:
import UIKit
class ViewController: UIViewController {
let watch = Stopwatch()
#IBOutlet weak var elapsedTimeLabel: UILabel!
#IBAction func startButton(_ sender: Any) {
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.updateElapsedTimeLabel), userInfo: nil, repeats: true)
watch.start()
}
#IBAction func stopButton(_ sender: Any) {
watch.stop()
}
#objc func updateElapsedTimeLabel (timer : Timer) {
if watch.isRunning {
let minutes = Int (watch.elapsedTime/60)
let seconds = watch.elapsedTime.truncatingRemainder(dividingBy: 60)
let tenOfSeconds = (watch.elapsedTime * 10).truncatingRemainder(dividingBy: 10)
elapsedTimeLabel.text = String (format: "%02d:%02d:%02d", minutes, seconds, tenOfSeconds)
} else {
timer.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override var prefersStatusBarHidden: Bool {
return true
}
}
The Stopwatch View Controller code:
import Foundation
class Stopwatch {
private var startTime : Date?
var elapsedTime: TimeInterval {
if let startTime = self.startTime {
return -startTime.timeIntervalSinceNow
} else {
return 0
}
}
var isRunning: Bool {
return startTime != nil
}
func start() {
startTime = Date()
}
func stop() {
startTime = nil
}
}
There is nothing at all coming in the debug window, so not sure what the issue is, I reconnected the buttons over and over so it's not that. I also get no other errors in the code as mentioned above.
Can anyone shed some light on this. Maybe I am using the wrong #selector or I am doing the updateElapsedTimeLabel minutes, seconds, tenOfSeconds calculations wrong. Not sure. Thanks for having a look.
If you Option-click on seconds and tenOfSeconds you will find that one is of type TimeInterval (i.e. Double) and the other is of type Double. So your format specifier of %02d was wrong. In C, a mismatch between the format specifier and the argument is undefined behavior. Swift doesn't say how it handles that but I guess it will ignore the argument.
To fix it, change your format specifier for the last 2 components to %02.f:
let minutes = Int(watch.elapsedTime/60)
let seconds = watch.elapsedTime.truncatingRemainder(dividingBy: 60)
let tenOfSeconds = (watch.elapsedTime * 100).truncatingRemainder(dividingBy: 100) // fixed the math here
elapsedTimeLabel.text = String(format: "%02d:%02.f:%02.f", minutes, seconds, tenOfSeconds)
But why not use a DateFormatter to make your life simpler:
class ViewController: UIViewController {
private let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "mm:ss:SS"
return formatter
}()
#objc func updateElapsedTimeLabel (timer : Timer) {
if watch.isRunning {
elapsedTimeLabel.text = formatter.string(from: Date(timeIntervalSince1970: watch.elapsedTime))
} else {
timer.invalidate()
}
}
}

Carrying Elapsed Time over to another ViewController

I have a small elapsed timer in my game and it works very well. However I am trying to figure out how to save the elapsed time when you die so I can carry it over to the Game Over Screen where the Score and High Score is displayed.
I tired a few things but none of them seem to work. I guess it's because the time is not being saved anywhere when the it's game over, but rather just reset to 00:00:00 when the game restarts.
I use two view Controllers for this timer. One is called Stopwatch the other code is in the GameScene. Here are the codes.
I wanna bring it into a label like for example:
let timeLabel = SKLabelNode(fontNamed: "Planer")
timeLabel.text = "Time: \(savedTimer)"
timeLabel.fontSize = 100
timeLabel.fontColor = SKColor.white
timeLabel.zPosition = 2
timeLabel.position = CGPoint (x: self.size.width/2, y: self.size.height * 0.5)
self.addChild(timeLabel)*/
Stopwatch.swift code
import Foundation
class Stopwatch {
private var startTime : Date?
var elapsedTime: TimeInterval {
if let startTime = self.startTime {
return -startTime.timeIntervalSinceNow
} else {
return 0
}
}
var isRunning: Bool {
return startTime != nil
}
func start() {
startTime = Date()
}
func stop() {
startTime = nil
}
}
And the code I got speed out through my Game Scene:
import UIKit
class ViewController: UIViewController {
private let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "mm:ss:SS"
return formatter
}()
let watch = Stopwatch()
#IBOutlet weak var elapsedTimeLabel: UILabel!
#IBAction func startButton(_ sender: Any) {
Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.updateElapsedTimeLabel), userInfo: nil, repeats: true)
watch.start()
}
#IBAction func stopButton(_ sender: Any) {
watch.stop()
}
#objc func updateElapsedTimeLabel (timer : Timer) {
if watch.isRunning {
elapsedTimeLabel.text = formatter.string(from: Date(timeIntervalSince1970: watch.elapsedTime))
} else {
timer.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override var prefersStatusBarHidden: Bool {
return true
}
}
What I understand is that you're trying to save the elapsedTime of your watch after the user taps the stop button. If that's the case, in your stopButton function you are calling watch.stop(), which in turn resets the startTime = nil. So you might want to edit it like so:
// Create a new class variable to store the time
var savedTime: TimeInterval? = nil
#IBAction func stopButton(_ sender: Any) {
savedTime = watch.elapsedTime
// Use the savedTime here to pass to the game over function
watch.stop()
}
If you don't need to save the time in your ViewController class, you can move the savedTime variable to a local one in the stopButton function.

EXC_BAD_ACCESS Code=2 Swift iOS

When developing an iOS app I come across random (sometimes occurring, sometimes not) EXC_BAD_ACCESS error in the following code:
import UIKit
class OrderTripDetailsController: UIViewController, OrderAware {
var order: Order?
var orderService = OrderService()
// MARK: Properties
#IBOutlet weak var driverName: UILabel!
#IBOutlet weak var autoColor: UILabel!
#IBOutlet weak var autoPlates: UILabel!
#IBOutlet weak var autoBrandModel: UILabel!
#IBOutlet weak var map: YMKMapView!
// MARK: Actions
// MARK: Navigation
override func viewDidLoad() {
if let cab = order?.orderCab {
autoColor.text = cab.cab.auto.color.name
autoPlates.text = cab.cab.auto.plates
driverName.text = cab.cab.driver.fullname
autoBrandModel.text = "\(cab.cab.auto.brand) \(cab.cab.auto.model)"
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
orderService.controllerDelegate = self
orderService.startSync()
}
override func viewWillDisappear(animated: Bool) {
orderService.stop() // <-- this is the line that fails
super.viewWillDisappear(animated)
}
// MARK: Order Aware
func setOrder(order: Order){
self.order = order
}
}
OrderService
Order Service is a class that starts timer and stops it. After stop is called, sometimes EXC_BAD_ACCESS occurs
import Locksmith
import RealmSwift
class OrderService {
// MARK: delegates
var controllerDelegate: UIViewController?
// Get the default Realm
let realm = try! Realm()
var timer = NSTimer()
//MARK: Domain actions
//repeat every n time if any dfound
#objc func initOrderSync(timer:NSTimer) {
func onRemoteReceived (order: Order) -> Void {
debugPrint("remote received", order.id)
if let o = realm.objectForPrimaryKey(OrderPo.self, key: order.orderHash) {
if o.orderStatus != order.orderStatus {
debugPrint("order status updated", order.id, order.orderStatus)
OrderUtils.navigateToOrderStatus(order,
viewController: controllerDelegate!)
}
try! realm.write {
o.orderStatus = order.orderStatus
}
}
}
if let authToken = AuthUtils.getToken() {
let orders = getOrdersByStatuses(OrderUtils.activeStatuses)
if orders.count > 0 {
for o in orders {
OrderRemoteService().getOrderFromRemote(o.id!, token: authToken, callback: onRemoteReceived)
}
} else {
debugPrint("invalidating timer; no orders")
stop()
}
} else {
debugPrint("invalidating timer; no auth")
stop()
}
}
func startSync() {
if !self.timer.valid {
debugPrint("starting order sync", controllerDelegate?.restorationIdentifier)
self.timer = NSTimer.scheduledTimerWithTimeInterval(20, target: self, selector: Selector("initOrderSync:"), userInfo: nil, repeats: true)
} else {
debugPrint("sync is already started", controllerDelegate?.restorationIdentifier)
}
}
func stop() {
dispatch_async(GlobalMainQueue, {
if self.timer.valid {
self.timer.invalidate()
debugPrint("invalidated timer", self.controllerDelegate?.restorationIdentifier)
} else {
debugPrint("sync is already stopped", self.controllerDelegate?.restorationIdentifier)
}
})
}
// MARK: orders
func getOrders() -> Results<OrderPo> {
return try! realm.objects(OrderPo.self).sorted("orderTime")
}
func getOrdersByStatuses(statuses: [String]) -> Results<OrderPo> {
var qString = "'\(statuses.first!)'"
if statuses.count > 1 {
for s in 1...statuses.count-1 {
qString += ",'\(statuses[s])'"
}
}
return try! realm.objects(OrderPo.self).filter("orderStatus IN {\(qString)}").sorted("orderTime")
}
}
Could anyone help with any ideas why it might happen?
Update 20.08.2016
Found out that OrderService is being deinitialised after 10 seconds for some reason.

EXC_BAD_ACESS crash xcode

I'm getting this crash : link
in my app ,i did many search abou it but i didn't find how to solve it.
i also enabled Zombies object & Analyzer of xcode but without succes.
Here is my code :
import UIKit
class CameraViewController: UIViewController{
#IBOutlet weak var playerContainer: UIView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var loading: UIActivityIndicatorView!
var device : GTLUserendpointGeneralCamera!
var myfoxCam : CloseliCameraDevice!
var retryToPlayCount = 0
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,selector: "playerStatusChanged:",name: CameraPlayerStatusChangedNotification,object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,selector: "playerStoppedDispose:",name: CameraPlayerStoppedNotification,object: nil)
}
override func viewDidAppear(animated: Bool) {
if(device.brand == "myfox"){
showLive()
}
}
override func viewWillDisappear(animated: Bool) {
MyFoxManager.sharedInstance.destroyPlayer()
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func showLive(){
loading.startAnimating()
MyFoxManager.sharedInstance.showLive(myfoxCam , image: self.imageView)
}
func playerStatusChanged(notification: NSNotification){
let waiting = notification.userInfo!["NSLocalizedDescription"] as! Bool
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if let strongSelf = self {
if(waiting){
strongSelf.loading.startAnimating()
}else{
strongSelf.retryToPlayCount = 0
strongSelf.loading.stopAnimating()
}
}
}
}
func playerStoppedDispose(notification: NSNotification){
let code = notification.userInfo!["NSLocalizedFailureReason"] as! Int
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if let strongSelf = self {
if(code & strongSelf.retryToPlayCount < 4){
strongSelf.retryToPlayCount = strongSelf.retryToPlayCount + 1
strongSelf.performSelector("showLive", withObject: nil, afterDelay: 2.0)
}
}
}
}
}
And
import UIKit
import Foundation
import CoreBluetooth
class MyFoxManager: NSObject {
static let sharedInstance = MyFoxManager()
var closeSDK : CloseliSDK!
var login = false
private override init() {
closeSDK = CloseliSDK(productKey: MyFoxAppId, withPassword: MyFoxAppSecret, serverType: "us")
}
func getCamera(device: GTLUserendpointGeneralCamera) -> CloseliCameraDevice? {
if(!login){
do {
try closeSDK.loginWithToken(device.appUrl, withAccount: device.url)
login = true
}catch{
return nil
}
}
do {
let myfoxCameras = try closeSDK.getCameraListError()
let myfoxCamera = myfoxCameras.filter{$0.deviceUUID == device.idDevice}
return myfoxCamera[0] as? CloseliCameraDevice
}catch {
return nil
}
}
func showLive(myfoxCam: CloseliCameraDevice, image: UIImageView){
closeSDK.preparetoLivePreview(myfoxCam , withUI: image)
}
func destroyPlayer(){
closeSDK.destoryPlayer()
}
}
Notification definition from third-party library :
/**
Notification for live preview status changing.
NOTICE: The notification may not be sent by CloseliSDK, so please fill parameter with sender to nil when adding observer
#param userInfo in NSNotification is a NSDictionary, value for NSLocalizedDescriptionKey is a NSNumber, YES means live preview is buffering, NO means live preview begin.
BOOL bWaiting = [[[notification userInfo] valueForKey:NSLocalizedDescriptionKey] boolValue];
*/
extern NSString *const CameraPlayerStatusChangedNotification;
/**
Notification for player stopped.
NOTICE: The notification may not be sent by CloseliSDK, so please fill parameter with sender to nil when adding observer
#param userInfo in NSNotification is a NSDictionary, value for NSLocalizedFailureReasonErrorKey is a NSNumber, represent the reason why it stopped, normally 0.
long stopReason = [[[notification userInfo] valueForKey:NSLocalizedFailureReasonErrorKey] longValue];
stopReason: 0x3261-means there is another client playing in p2p mode.
*/
extern NSString *const CameraPlayerStoppedNotification;
Any idea ?
Thanks in advance

Resources