I need write some code for my app(in Swift) that should be executed before app termination. It works when I use appWillTerminate in appDelegate when it's not in background but I need it to run the code when it terminates in both background or foreground. How can I do it ??
The following strategy might work, and it's a more of a pure Swift language approach to take than an iOS one: Every class can override the deinit method. Whenever the class needs to be freed from the heap, the de-initializer is called before the class is freed. This could happen such as when the class falls out of scope, and has no more retain counts. This will probably happen for your AppDelegate when your app is terminating.
You can put your code in this method beginBackgroundTaskWithName:expirationHandler: in applicationDidEnterBackground. This method give to your application extra time for finishing some task what you need to finish. More documentations is here Executing Finite-Length Tasks : https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
If app is in background and don't have any task executing, then the app is in suspend.
When app is in suspend, terminate app will not call applicationWillTerminate. But ,you can start background task
or enable background modes.
e.g.
func applicationDidEnterBackground(_ application: UIApplication) {
bgTask = application.beginBackgroundTask(withName: "MyTask") {
application.endBackgroundTask(self.bgTask!)
self.bgTask = UIBackgroundTaskInvalid
}
}
Related
when I terminate my app into twice tap on home button then how can I call my function in background service on swift 4.
because I work on local push notification , after API calling then getting data and that's data put into notification.
I am not entirely sure this is what you mean, but if you want to call a function/do something right before your app enters the background(what happens when someone double clicks the home button) you can use the default applicationWillResignActive(_:) or applicationDidEnterBackground(_:) function in the AppDelegate class. See the apple docs for more information about app states and functions.
If you want to execute code when the app terminates, use applicationWillTerminate(_:).
So in AppDelegate.swift(I deliberately left the original Xcode default comment in for clarification):
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
yourGoToBackgroundFunction()
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
yourSaveDataFunction()
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
yourSaveDataFunction()
}
}
Were the delegate property ever to be nil, the app would be in an unrecoverable state.
class UIApplication
Declaration
unowned(unsafe) var delegate: UIApplicationDelegate?
Discussion
Every app must have an app delegate object to respond to app-related messages. For example, the app notifies its delegate when the app finishes launching and when its foreground or background execution status changes. Similarly, app-related messages coming from the system are often routed to the app delegate for handling. Xcode provides an initial app delegate for every app and you should not need to change this delegate later.
Why is UIApplicationDelegate.delegate defined as an optional? A nil value would be non-recoverable?
Actually, if I were to subclass UIApplication then I might be able to recover from delegate set to nil? Is this maybe why?
Here is a related question, but the AppDelegate is what holds the entire app together. I don't think it could be nil.
One reason might be to prevent AppDelegate from messing up with your unit tests.
Normally, when you are running unit tests, you actually don't ever have to interact with any UI components drawn onto screen so, initializing application's window property is totally unnecessary. Moreover, the code written in AppDelegate.swift (such as function calls in application(application:didFinishLaunchingWithOptions) might cause your unit tests to not run as intended so you may want the application delegate to never be instantiated.
For a typical iOS application, UIKit creates the application with the following function in main.swift:
UIApplicationMain(Process.argc, Process.unsafeArgv,
NSStringFromClass(UIApplication), NSStringFromClass(AppDelegate))
(As of Xcode 6, it is handled by the #UIApplicationMain decorator.)
UIApplicationMain initializes the application object and the application delegate whose type is the class name you passed to it, and sets up the event cycle. It's totally up to you to have it create the delegate object for you. If you don't need AppDelegate's UIWindow property, or any callback methods about handling push notifications, application's state etc., you create the application without it:
UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), nil)
So that being said, if your unit tests don't depend on any of AppDelegate's methods to run, you can update main.swift as follows:
var delegateClassName: String? = NSStringFromClass(AppDelegate)
if NSClassFromString("XCTestCase") != nil {
// Unit tests are being run, so don't execute any code written in AppDelegate.swift
delegateClassName = nil
}
UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), delegateClassName)
In order to know why/how this works you would have to know how UIApplication works internally, so any idea as to why or why not it's optional is purely conjecture.
There's likely a point where if the delegate is nil, the application either quits or crashes, or it's simply to allow initialization without setting the delegate and they chose not to force unwrap it so they can handle the error case.
I am creating a simple application which perform some task on main thread. I am printing process in NSLog so I can understand that my process is running or not.
Now when I press home button without starting the process (Process will be start when I tap on a button) application enters in background and my both of methods applicationDidEnterBackground & applicationWillResignActive are being called.
But when I first tap on my button and process starts on main thread after that if I press home button none of these two method being called. So my application can't know that app entered in background or not.
Even after that when I again active the app it shows me a black screen with status bar only.
Why this is happening?
Why app not entering in background?
Why apple's methods not being called?
Is there a way to solve it?
UPDATE
Here is my appdelegate class code
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
All methods have no implementation.
Thanks in advance.
I am creating a simple application which perform some task on main thread.
Don't perform long-running operations on the main thread.
The delegate callbacks happen on the main thread. If the main thread is busy, then the callbacks won't happen until you return to the "run loop".
When foregrounding your app, the OS actually displays a screenshot if available, falling back to the launch image (Default.png). The screenshot is taken after -applicationDidEnterBackground: returns, which allows you to customize what gets saved (you might want to do this for security reasons, or to hide UI elements which might not make sense to show when relaunching e.g. a countdown timer).
The black screen is probably because your app has no launch image. If your app takes more than about 10 seconds to enter the background (and it does, since the main thread is blocked), it gets killed. Except the debugger is attached and catches SIGKILL, so it's easy to miss unless you're watching Xcode.
there are some cases
if UIApplicationExitsOnSuspend key set to true in your app's Info.plist, the applicationWillResignActive method is not called when the user hits the home button. and may b some thing other. check keys here Apple keys and see if something new you added to plist. and there is no other case that you say your delegate method not calling. it may also some time due to project in appropriate behavior. try cleaning your project and rebuild.
this is going to sound strange but for those it helps. I had the same issue and cleaned my project and then it started working again.
My app delegate method applicationDidBecomeActive: is getting called twice for the first time launch of the application. I have some portion of code which I want to execute only once & that I have put into applicationDidBecomeActive:
What should I do?
I got the issue. I am using Location Services. When launching for the first time after I tap on "OK" on the location services alert, my applicationDidBecomeActive gets called one more time which is the normal iOS behavior.
If you want to call your code only once when app becomes active, try calling it from two methods.
didFinishLaunchingWithOptions
applicationWillEnterForeground
instead of calling it only from applicationDidBecomeActive.
This is because of location or push notification alert.
After the native location/push notification has been dismissed, applicationDidBecomeActive will be called.
I don't know if this will help, but I just had the same issue with a totally simple app that doesn't use Location Services, and I found out it's an illusion. Look at the logging messages I got:
2012-12-22 10:47:45.329 Bizarro[10416:907] start applicationDidBecomeActive:
2012-12-22 10:47:45.333 Bizarro[10416:907] end applicationDidBecomeActive:
2012-12-22 10:47:45.329 Bizarro[10416:907] start applicationDidBecomeActive:
2012-12-22 10:47:45.333 Bizarro[10416:907] end applicationDidBecomeActive:
Look closely. Look at the times. The first and third messages have the same time. The second and fourth messages have the same time. They are the same messages! It's an Xcode bug; it has nothing to do with my code. Xcode is reporting the same log messages twice.
In my case, I was able to prevent this by turning off all Behaviors for Running -> Generates Output.
What about:
Increment on applicationDidBecomeActive
Decrement on callback events of permissions requests or other alerts that trigger another applicationDidBecomeActive when closed.
With Xcode 6 there's a new reason this can happen: when you launch an app in a resizable simulator, applicationDidBecomeActive: will get called twice.
It launches the app with the default size class, and then applies the size you were last using—even if you were using the defaults. Any time a change in size class is applied, applicationDidBecomeActive: gets called.
When app launches first time
it calls sequentially,
didFinishLaunchingWithOptions
applicationDidBecomeActive (Twice)
When we open the Control Center it calls only,
applicationDidBecomeActive
When app come from background to foreground it calls sequentially
applicationWillEnterForeground
applicationDidBecomeActive
I'm currently seeing double notifications.
It's happening because my AppDelegate's init code is being called twice.
It's being called once when the main() does [[NSBundle mainBundle] loadNibNamed:#"MainMenu" owner:application topLevelObjects:&tl] (ie, when the .XIB file is loaded), becaues the .XIB file is setting up FirstResponder to my custom AppDelegate, and then it's being called again when main() calls [[myAppDelegate alloc] init].
The init code is what does the addObserver calls, so two observers are being set up for each notification I care about, which is why my notifications get called twice.
I'm a newbie OS X programmer, so I'm not yet sure of the best way to resolve these two, but wanted to post it here in case it's of help to others, another place to look.
Have you possibly created an instance of your class in Interface Builder AND in your AppDelegate code, perhaps?
If you have code you want called only once when the app starts up, then use
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
instead.
Otherwise, applicationDidBecomeActive will be called whenever your app becomes active again, so that doesn't just mean twice as in your case, but every time the user switches back to your app after switching to another.
If you use RxSwift, then you can just throttle the application event, so it doesn't call twice in the same second:
NotificationCenter.default.rx.notification(Notification.Name.UIApplicationDidBecomeActive)
.throttle(1, scheduler: MainScheduler.instance)
.subscribe { (event) in
self.appEnteredFromBackground()
}.disposed(by: disposeBag)
private func appEnteredFromBackground() {
Analytics.trackPageView(withScreen: .home)
dataStore.checkIfAllowingRides()
}
I put this code in my actual view controller where the logic is supposed to happen on ApplicationDidBecomeActive.
I just check at top of applicationDidBecomeActive: if the request was really sent (I made a function for this, checking status), if so I return already.
The second time in applicationDidBecomeActive:, the function reads the status as Deny or Allowed, because this is after the User answered the Alert.
In my app from applicationDidEnterBackground i want to ask the application for more time to
create a UIWebView and load request with UIBackgroundTaskIdentifier, then in the delegate
method of UIWebView (webViewDidFinishLoad) i want to do a stuff there and show an alert or
notification while the
application is still reining in the background .
so how i can do that?.
Apple's documentation for UIApplication class for beginBackgroundTaskWithExpirationHandler: method says:
You can call this method at any point in your application’s execution.
You may also call this method multiple times to mark the beginning of
several background tasks that run in parallel. However, each task must
be ended separately. You identify a given task using the value
returned by this method.
This method can be safely called on a non-main thread.
So, once web view finish loading in background you can trigger another operation from webViewDidFinishLoad to show alert.
When you receive applicationDidEneterBackground your app is already effectively in the background. At that moment all your networking should be closed and you really shouldn't try to show any alerts or notifications.