What function gets called when loading app from homescreen? - ios

I want to be able to change the background color of my app depending on the time of day. I believe the way to go about this is saying if the hour component is greater than whatever number, set the background to the nighttime background, otherwise it's the daytime background.
To test out what I was worried about, I threw
timeLabel.text = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .FullStyle)
into viewDidLoad. This shows the time that the app loads. This also obviously keeps updating if I kill the app and reload it completely.
However, if the user goes the the home screen or goes to a different app, then comes back to this the time isn't going to be updated. It will show the time the app was first loaded up. Only if the user completely kills the app, which obviously can't be relied on, will the correct time be shown.
So in my example if my "switch to nighttime time" was 5pm, if the user loads up at the at at 4:30 and then goes to the homescreen, loads up the app at 5pm, nothing will be changed as the stored time will still be 4:30.
I tried throwing the code in viewDidAppear and nothing changed.
What code is run when the app is loaded up from being on the homescreen or coming back from another app?

You want to key off of the UIApplicationDidBecomeActiveNotification event. Try this:
override func viewDidLoad()
{
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "applicationDidBecomeActive:",
name: UIApplicationDidBecomeActiveNotification,
object: nil)
}
func applicationDidBecomeActive(notification: NSNotification)
{
// do something when the app is active again.
timeLabel.text = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .FullStyle)
}

The method -applicationWillEnterForeground: in your application delegate will be called every time a user enters your app.

You'll want to look at using NSCalendar for this:
let currentDate = NSDate() // You can input the custom as well
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: NSDate())
let currentHour = components.hour // You can play around with the ""components""
The following method is what you're after:
applicationDidBecomeActive: it's called every time a user opens the app.

Related

How to check how long ago was the app last opened

In my app, I want to check how long ago did the user last open the app and if it was 14 days or more, the user would receive a prompt saying they should be more active but I'm not too sure how to check how long ago was the app last used.
Store the current date in UserDefaults whenever the app becomes inactive (using the applicationWillResignActive app delegate).
Load the stored date (if any) from UserDefaults whenever the app becomes active (using the applicationDidBecomeActive app delegate). If there is a date (there won't be the first time the app is used), calculate the number of days between the retrieved date and the current date.
See Swift days between two NSDates for methods to calculate the difference between two dates. In short, you use the Calendar dateComponents(_, from:, to:) method.
In your AppDelegate:
func applicationWillResignActive(_ application: UIApplication) {
UserDefaults.standard.set(Date(), forKey: "LastOpened")
}
func applicationDidBecomeActive(_ application: UIApplication) {
guard let lastOpened = UserDefaults.standard.object(forKey: "LastOpened") as? Date else {
return
}
let elapsed = Calendar.current.dateComponents([.day], from: lastOpened, to: Date())
if elapsed >= 14 {
// show alert
}
}
save current Date(UserDefaults) on applicationWillTerminate(_:) & applicationDidEnterBackground(_:) methods.
check it on application(_:didFinishLaunchingWithOptions:)

How to measure how long specific actions take to complete for users in iOS app

I have an iOS app that I wrote with Swift with Firebase Auth/DB for the backend. I would like to measure how long it takes for a user to complete specific actions. I'm actually not interested in the response time, but am interested in the total time it takes to complete something.
In other words, I want to measure how long it takes to login, click on a button, receive a push notification, click "Ok" on that notification, etc. I also want to log how many seconds it took to get from one thing to the next (i.e. login time: 2.5 seconds, time to push a specific button: 4 seconds, etc.).
I am trying out Firebase Analytics, and it almost works, but not quite. I can log specific events, such as login, button presses, etc., but it just logs the that the event occurs, not how long it took.
Ideally, I would record all of this data on the specific users I give to try my app, so I could look at all the data, find averages and other useful information.
consider using a a Timer, maybe something like this.
import UIKit
class Whatever: UIViewController {
var timer = Timer()
var currentTime = 0.00
func timeCounter() {
currentTime += 0.01
}
override func viewDidLoad() {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(Whatever.timeCounter), userInfo: nil, repeats: true)
}
#IBAction func buttonPressed(_ sender: Any) {
timer.invalidate()
//whatever button does
}
}
This way when the application begins the timer will begin, when the final button is pushed the timer will stop. You will have the value of how long it took stored as currentTime.
Hope this helps!

Local banner notification for terminating App

I want to show banner notification when user quits the Application. And on tapping that banner I want my Application to open.
func showBanner() {
UIApplication.shared.cancelAllLocalNotifications()
let notif = UILocalNotification.init()
notif.alertBody = "Your Message Here..."
localNotif.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.presentLocalNotificationNow(notif)
}
If I put this code in applicationDidEnterBackground it works fine; But, when I put it in applicationWillTerminate, it doesn't.
Any workaround?
EDIT:
Added fireDate like following:
var dc = DateComponents()
dc.second = 2 // 2 seconds from current date time
notif.fireDate = Calendar.current.date(byAdding: dc, to: Date())
Still not working. Any idea?
The same code works when I set in App communicates using CoreBluetooth in info.plist for Requires Background Modes.
Got the hint from This Answer
Let's hope, Apple does not reject my App.
no guarantee that applicationWillTerminate will ever get called may that is the reasone your code not working . so if your need to do anything before app exist then call applicationDidEnterBackground
more check this iOS - How to guarantee that applicationWillTerminate will be executed

iOS disable UIButton for 30 minutes

I am making an app where people can request two orders per hour maximum. I would like to disable the "Order" UIButton for a full 30 minutes once it is pressed. Can anybody suggest the most efficient way to do this but that fully prevents the user from ordering twice even if the app is killed? Thanks.
At a high level you need to do two things:
Calculate the NSDate for when the button should be enabled again and store that date in NSUserDefaults.
Start an NSTimer that goes off in 30 minutes. Enable the disabled button when the timer goes off and remove the date from NSUserDefaults.
More than likely the app will go into the background and the timer will stop long before the 30 minutes. This means that your app needs to stop the timer when it goes into the background. And when it returns to the foreground, you look at the date in NSUserDefaults and see how much time is left. If the time is already past, enable the button and delete the date from NSUserDefaults. If not, start another timer to go off after the needed amount of time as in step 2 above.
Here's the approach I thought of earlier to your problem. The three things you'll use are NSDate, NSTimeInterval, and NSUserDefaults
// I threw this in Xcode to aide me in typing this solution.
// You probably dragged a button from storyboard...leave it like that.
let orderButton: UIButton?
// Put toggleOrderButtonAvailability() in viewDidLoad and viewDidAppear
func toggleOrderButtonAvailability() {
// get current date
let currentDate = NSDate()
// we're not sure if there's a value for this, but we're creating a variable for it
// it will nil if the user hasn't placed an order
var lastOrderDate: NSDate?
// we're creating a variable to check
var timeSinceLastOrder: NSTimeInterval?
// if a value for the lastOrderDate saved in NSUserDefaults, then...
if NSUserDefaults.standardUserDefaults().objectForKey("lastOrderDate") != nil {
lastOrderDate = NSUserDefaults.standardUserDefaults().valueForKey("lastOrderDate") as? NSDate
// calculate minutes since last order
// 1800 seconds = 60 seconds per minute X 30 minutes
timeSinceLastOrder = (currentDate.timeIntervalSinceDate(lastOrderDate!)) / 1800
if timeSinceLastOrder < 30 {
orderButton?.enabled = false
// Some alert to let the user know they can't order for another X minutes
// TODO: you could create a class variable like "timeUntilButtonReenabled"
// and set it here, then the timer would run and call this method when it's
// done to re-enable the button. Set the timer in viewDidAppear()
} else {
orderButton?.enabled = true
}
}
}
You'll also want to set the lastOrderDate when you place an order and you can call the method we just created to disable the button when you place an order.
#IBAction func orderButtonAction(sender: UIButton) {
// Whatever you do when you send an order
// Set the lastOrderDate & disable the button
let currentDate = NSDate()
NSUserDefaults.standardUserDefaults().setObject(currentDate, forKey: "lastOrderDate")
toggleOrderButtonAvailability()
}
You should save the order date in NSUserdefaults.Once app launched,check the last order date and make an count down timer for that.
When the button is pressed, disable the button and log the current time using an NSDate object. To ensure it persists even if the app is killed, make sure you write it-- if you're app isn't already using a data system, NSUserDefaults is probably the easiest way to get about this.
Next, you need to create a mechanism for the button to enable again. The easiest reliable method to do so is by creating an NSTimer that checks whether or not the logged date is over 30 minutes ago, and if so, enable the button.
Here's an example of how to do this in Swift:
class ViewController: UIViewController {
#IBOutlet weak var btn: UIButton!
var enableTimer: NSTimer!
let defaults = NSUserDefaults.standardUserDefaults()
//Because this is a computed property, it auto-saves and persists
var lastPushed: NSDate {
get {
if let unwrappedDate = defaults.objectForKey("lastPushed") as? NSDate {
return unwrappedDate
} else { //If date not yet set
return NSDate(timeIntervalSince1970: 0)
}
} set { //NSDate is already compatible with NSUserDefaults
defaults.setObject(newValue, forKey: "lastPushed")
}
}
override func viewDidLoad() {
startTimer()
}
func startTimer() {
enableTimer = NSTimer.scheduledTimerWithTimeInterval(30, self, Selector("enableTim:"), nil, true)
}
#IBAction btnPressed() {
lastPushed = NSDate() //NSDate with current time
startTimer()
btn.enabled = false
}
func enableTim(timer: NSTimer) {
if (lastPushed.timeIntervalSinceNow < -1800) { //If last pressed more than 30 minutes ago
btn.enabled = true
enableTimer.stop()
}
}
}

Best way to implement iOS badge notifications in Tab Bar

Generally speaking I want to query my DB for all new FeedItems in the last 10 minutes. This Feed should have a nice batch of new FeedItems every 10 minutes.
I've written a function:
func getRecentFeedItems() {
// Set up timing
let date = NSDate()
let calendar = NSCalendar.autoupdatingCurrentCalendar()
let dateMinusTenMin = calendar.dateByAddingUnit(.Minute, value: -10, toDate: date, options: [])
//Query the DB
let getRecentFeedItems = FeedItem.query()
getRecentFeedItems!.whereKey("createdAt", greaterThan: dateMinusTenMin!)
let newBadgeCount: Int = (getRecentFeedItems?.countObjects())!
if newBadgeCount > 0 {
self.navigationController?.tabBarItem.badgeValue = String(newBadgeCount) //update the Badge with the new count
print("update the badge with \(newBadgeCount)")
} else {
self.navigationController?.tabBarItem.badgeValue = nil
}
}
This function works to update the Badge Notification however when I set a timer for it to run every ten minutes:
var updateBadgeQueryTimer = NSTimer.scheduledTimerWithTimeInterval(600.0, target: self, selector: Selector("updateBadgeQuery"), userInfo: nil, repeats: true)
It does work, but I get the following warning which I know to be a serious one:
Warning: A long-running operation is being executed on the main thread.
Given the following parameters:
If user is on Tab1 where the FeedItems, the query runs and the badge is populated, I want the Badge to show up and then disappear when the user reloads the feed via UIRefreshControl()
If user is on Tab2 or another View, I want the Badge to show up and only disappear when user presses Tab1.
I want the query for the amount of new items to run every 10 minutes.
I've tried running getRecentFeedItems() in viewWillAppear as well as viewDidAppear().
Is there a better way to do this?
As far as I can tell the only thing you'll need to change is to run getRecentFeedItems in the background and only update the badge value after you get a success or failure message from the query. This will prevent the warning of an operation occurring on the main thread.
Hope this helps!

Resources