AppDelegate Issues When Running App on Device - ios

I have an app that has a simple timer that runs on an animated viewcontroller using SpriteKit. I want the timer to continue so I used the Notification Center and posted notifications in the AppDelegate as follows:
func applicationWillResignActive(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName("stopTimerNotification", object: nil)
}
func applicationDidEnterBackground(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName("stopTimerNotification", object: nil)
}
func applicationWillEnterForeground(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName("startTimerNotification", object: nil)
}
func applicationDidBecomeActive(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName("startTimerNotification", object: nil)
}
My timer runs fine on the device when connected to Xcode and also runs fine on device when the "Sleep Time" app is running on device (and not connected to Xcode). I've searched but cannot fathom this one out. Any suggestions?
The code that executes when both NSNotifications are called is:
func stopTimerInBackground(note: NSNotification) {
if(isRunningStopwatch == true) {
stopPressed()
stopTimerInBackgroundDate = NSDate()
}
}
func startTimerInBackground(note: NSNotification) {
var restartTimerInBackgroundDate:NSDate! = NSDate()
if (isStopwatch == true) {
previousElapsedTime = restartTimerInBackgroundDate.timeIntervalSinceDate(stopTimerInBackgroundDate)
previousElapsedTime = 0
startPressed()
}
}
I just wonder if it's a plist value I have to change?

Related

AudioKit Background Audio Battery Usage

I just switched from AVAudio to AudioKit. To get things working I had to enable background audio and since then battery usage is woeful.
What is the best way to clean up and come out of background audio once a sequence or player has come to and end?
Any help would be greatly appreciated.
In your app delegate:
func applicationDidEnterBackground(_ application: UIApplication) {
conductor.checkIAAConnectionsEnterBackground()
}
func applicationWillEnterForeground(_ application: UIApplication) {
conductor.checkIAAConnectionsEnterForeground()
}
In your audio engine, or conductor (as per other AudioKit examples) do:
var iaaTimer: Timer = Timer()
func checkIAAConnectionsEnterBackground() {
if let audiobusClient = Audiobus.client {
if !audiobusClient.isConnected && !audiobusClient.isConnectedToInput {
deactivateSession()
AKLog("disconnected without timer")
} else {
iaaTimer.invalidate()
iaaTimer = Timer.scheduledTimer(timeInterval: 20 * 60,
target: self,
selector: #selector(self.handleConnectionTimer),
userInfo: nil, repeats: true)
}
}
}
func checkIAAConnectionsEnterForeground() {
iaaTimer.invalidate()
startEngine()
}
func deactivateSession() {
stopEngine()
do {
try AKSettings.session.setActive(false)
} catch let error as NSError {
AKLog("error setting session: " + error.description)
}
iaaTimer.invalidate()
AKLog("disconnected with timer")
}
#objc func handleConnectionTimer() {
AKLog("should disconnect with timer")
deactivateSession()
}

Send the location to the server every n minutes in the background in swift

i want to sent the location to the server when the app is background, i tried with many way but can't get the solution
I tried with the timer function using the timer and using function
self.bgtimer = Timer.scheduledTimer(timeInterval:60, target: self, selector: #selector(AppDelegate.bgtimer(_:)), userInfo: nil, repeats: true)
RunLoop.current.add(self.bgtimer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
but i when i stop the timer when the app becomes active
if UIApplication.shared.applicationState == .active {
RunLoop.current.cancelPerformSelectors(withTarget: self.bgtimer)
timer.invalidate()
}
but the app not function properly collection view and back function everything is not working properly
In DidBackground:
stop normalTimer.
start New backgroundTaskTimer
In WillForeground:
stop backgroundTaskTimer.
start normalTimer
Find below sample code:
In Appdelegate:
Declaration:
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
var backgroundTaskTimer:Timer! = Timer()
Implementation:
func doBackgroundTask() {
DispatchQueue.global(qos: .default).async {
self.beginBackgroundTask()
if self.backgroundTaskTimer != nil {
self.backgroundTaskTimer.invalidate()
self.backgroundTaskTimer = nil
}
//Making the app to run in background forever by calling the API
self.backgroundTaskTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.startTracking), userInfo: nil, repeats: true)
RunLoop.current.add(self.backgroundTaskTimer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
// End the background task.
self.endBackgroundTask()
}
}
func beginBackgroundTask() {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(withName: "Track trip", expirationHandler: {
self.endBackgroundTask()
})
}
func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
}
In ApplicationDidEnterBackground:
func applicationDidEnterBackground(_ application: UIApplication) {
//Start the background fetch
self.doBackgroundTask()
}
In ApplicationWillEnterForeground:
func applicationWillEnterForeground(_ application: UIApplication) {
if self.backgroundTaskTimer != nil {
self.backgroundTaskTimer.invalidate()
self.backgroundTaskTimer = nil
}
}

How do I reload UITableView data when the app comes to foreground? (Xcode 8.3 / Swift 3)

I have the following methods in my "ViewController" class to populate custom cells in a UITableView from a GET API call. This works fine when app first loads.
//ViewController
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loadDataInUITableViewCell()
}
func loadDataInUITableViewCell() {
apiCentral.sharedInstance.fetchData() {
result in
guard result.error == nil else {
self.handleError(result.error!)
return
}
if let fetchedData = result.value {
self.data = fetchedData
}
self.messagesTableView.reloadData()
}
}
How do I refresh the data when the app comes to the foreground? Well, I added the following to AppDelegate to run the "loadDataInUITableViewCell" method so that the data reloads.
//AppDelegate
let mainViewController = ViewController()
func applicationWillEnterForeground(_ application: UIApplication) {
mainViewController.loadDataInUITableViewCell()
}
ISSUE: The above mechanism works fine however, I get the following error when the app comes to the foreground.
"fatal error: unexpectedly found nil while unwrapping an Optional value"
The issue seems to be happening at "self.messagesTableView.reloadData()" line of code. I'm using Xcode 8.3 and coding in Swift 3. Any guidance would be appreciated. Thank you.
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
Write this above line in viewWillAppear()
func willEnterForeground() {
tableView.reloadData()
}
Used this above code in your ViewController where there is UITableView
Solutions 1. In appdelegate:
//AppDelegate
let mainViewController : ViewController?
func applicationWillEnterForeground(_ application: UIApplication) {
mainViewController.loadDataInUITableViewCell()
}
And in Your viewcontroller:
//ViewController
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
(UIApplication.sharedApplication().delegate as! AppDelegate).mainViewController = self
loadDataInUITableViewCell()
}
Solutions 2.
listen in viewcontroller:
//ViewController
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(ViewController.loadDataInUITableViewCell(), name: UIApplicationWillEnterForegroundNotification, object: nil)
loadDataInUITableViewCell()
}
UIApplicationWillEnterForeground Notification
Posted shortly before an app leaves the background state on its way to becoming the active app.
Discussion
The object of the notification is the UIApplication object. There is no userInfo dictionary.
Declaration
static let UIApplicationWillEnterForeground: NSNotification.Name
From Apple's Documentation.
It's super easy to use:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(self.handler), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}
func handler() {
// self.tableView.reloadData()
}
Hope it helps!

Pause NSTimer when app goes to background

I have the following in my touchesBegan function in my GameScene so that the timer only starts when the user touches a certain sprite:
let start = SKAction.runBlock({
NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "printDuration:", userInfo: NSDate(), repeats: true)
})
tapToStartNode.runAction(start)
and the following function:
func printDuration(timer: NSTimer) {
if self.view?.paused == false {
guard let userInfo = timer.userInfo else {
return
}
guard let startDate = userInfo as? NSDate else {
return
}
let duration = NSDate().timeIntervalSinceDate(startDate)
currentTime = NSDate().timeIntervalSinceDate(startDate)
currentTimeValueLabel.text = "\(NSString(format:"%3.2f", duration))"
}
}
However, when applicationDidEnterBackground or applicationWillResignActive the timer is not paused and continues to run when the app is in the backgorund. How do I make it stop?
Here a tips you can use for your problem
You can use func applicationDidEnterBackground(_ application: UIApplication) or func applicationWillResignActive(_ application: UIApplication) on AppDelegate
Access your controller by initialize rootViewController example :
let vc = self.window?.rootViewController as? ViewController
Then you can access your function (make sure function is on public state)
vc.pauseTimer() (customize based on your situation)
Hope it will be helpful

Check if Wifi Is Turned On While App is Active

I have an app using Reachability library to detect when wifi is turned on while the app is active. I have the following code sample below in my view controller. The view controller is loaded when the app becomes active. When I run this code on my iPhone the selector method is not called. What's wrong with this code and how do I fix it?
let reachability = Reachability.reachabilityForInternetConnection()
override func viewDidLoad() {
super.viewDidLoad()
println("view did load")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: "ReachabilityChangedNotification", object: reachability)
reachability.startNotifier()
}
func reachabilityChanged(note: NSNotification) {
// I don't see this line printed out!!!
println("selector method called")
let reachability = note.object as! Reachability
if reachability.isReachable() {
println("yay internet is on")
} else {
println("internet is off")
}
}

Resources