When the app is open or in background, I am using notification in appdelegate to update the message box table and then it is working.
Appdelegate (in didFinishLaunchingWithOptions and didReceiveRemoteNotification):
NSNotificationCenter.defaultCenter().postNotificationName("changeMessageBox", object: nil)
MessageViewController:
in viewdidload:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector (MessagesViewController.reloadtable), name: "changeMessageBox", object: nil)
func reloadtable()
{
clearArrays()
if (PFUser.currentUser()!["firebaseUID"] !== nil)
{
self.updateResultArray(PFUser.currentUser()!["firebaseUID"] as! String)
resultsTable.reloadData()
}
}
and data is refreshed in the message box.
But when the app is closed and i recieve a chat, the message box ( the window with messages from all the people not the individual chat) does not get updated.
I have to open the app, go to message box ,then back to main page and go back to message box again only then the table view gets refreshed.
Do you guys know what am i missing?
Try below code for post notification,
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in
NSNotificationCenter.defaultCenter().postNotificationName("changeMessageBox", object: nil)
})
I was having same issue and resolved like this. Hope this will help you.
Receiving Notification while app in closed or in suspended state will trigger
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
Try to post notification in this method. i guess it will update your view.
Additionally Refer this document if you have query with Notifiacation
http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/
Related
My user is redirected to their inbox when they verify their email. When they reopen the application I need to reload the user's data automatically. I used the following code to do so...
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
Auth.auth().currentUser?.reload()
}
However, this code only works if I completely close the application and reopen it. Is there a way for me to call this without having to close the application?
You can try didBecomeActiveNotification:
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
Auth.auth().currentUser?.reload()
}
A slightly different approach but should do the same,
In ViewDidAppear:
NotificationCenter.default.addObserver(self, selector: #selector(yourFunction), name: UIApplication.didBecomeActiveNotification, object: nil)
#objc function yourFunction(){
print("Returned from background")
// Do something
}
I use AVFoundation for a video recording. When the app goes to the background I stop the capture session and when it enters the foreground I restart the capture session, everything works fine. I also use callKit to listen for incoming phone calls and that works fine too:
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterBackground), name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
#objc func appWillEnterBackground() {
// if recording stop recording, stop timer, etc ...
captureSession.stopRunning()
previewLayer = nil
}
#objc func appWillEnterForeground() {
if !captureSession.isRunning {
captureSession.startRunning()
initialize preview layer
}
}
The problem is while the vc with the camera is active (recording or not) and when I swipe from the bottom to bring up the Control Center Screen or swipe from the top to bring down the Notification Center Screen UIApplication.willResignActiveNotification gets called and the capture session is stopped. When I remove either of those screens UIApplication.willEnterForegroundNotification doesn't get called and the capture session is no longer running.
What I want to do is when either of those screens surface I simply use a bool to prevent the capture session from stopping
var haveControlScreensSurfaced = false // toggle this true/false depending when the control screens enter and leave
#objc func appWillEnterBackground() {
if view.window != nil && haveControlScreensSurfaced { return }
// if recording stop recording, stop timer, etc ...
captureSession.stopRunning()
previewLayer = nil
}
How can specifically listen for Control Center Screen and Notification Center Screen activity so that I can toggle my haveControlScreensSurfaced bool value to true/false?
This way works good for an avplayer
Since I needed a capture session long story short I used this. When sliding up/down either the Notification Center Screen or the Control Screen, UIApplication.didEnterBackgroundNotification (app enters background) and UIApplication.willEnterForegroundNotification (app is about to enter foreground) never get called. I simply moved my code to there and problem solved:
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
#objc func didEnterBackground() {
// stop capture session
}
#objc func appWillEnterForeground() {
// start capture session
}
Here is a breakdown of what happens when the notifications are triggered:
Pressing the Home Button, sending app to the background:
1- `UIApplication.willResignActiveNotification` gets called first
2- `UIApplication.didEnterBackgroundNotification` gets called second // *** gets called when the HomeButton is pressed ***
Opening the app back up:
1- `UIApplication.willEnterForegroundNotification` gets called first // *** gets called when the opening the app back up ***
2- `UIApplication.didBecomeActiveNotification` gets called second
Sliding down the Notification Center Screen from the top:
1- `UIApplication.willResignActiveNotification` gets called first
2- `UIApplication.didBecomeActiveNotification` gets called second
3- if using the `.AVCaptureSessionWasInterrupted` the `.videoDeviceNotAvailableInBackground` gets called third
4- `UIApplication.willResignActiveNotification` gets called fourth
Sliding the Notification Center Screen back up:
1- `UIApplication.didBecomeActiveNotification` gets called alone
2- if using the `.AVCaptureSessionInterruptionEnded` it gets called second
Sliding the Control Screen up from the bottom:
1- `UIApplication.willResignActiveNotification` gets called alone
Sliding the Control Screen back back down:
1- `UIApplication.didBecomeActiveNotification` gets called by alone
I am sending local notifications to my users, and I want to show the relevant title on the notification settings button.
If local notifications are off, this title should be "Notifications: off", and if local notifications are on, this title should be something like "Preferences".
Right now I'm checking this in viewDidLoad and viewDidAppear, and it works.
if UIApplication.sharedApplication().currentUserNotificationSettings()?.types.rawValue == 0 {
//the first title
} else {
//the second title
}
Except one case. If my user is changing notifications in the phone settings from "on" to "off" or vice versa, and after that he is back — the title is not changing (because this viewController already loaded and did appear).
How could I check that user is back from the Settings?
You can observe this notification when your app is come to foreground from inactive, the selector will be called everytime your app is opened again from background:
Put in viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.reloadData), name: UIApplicationWillEnterForegroundNotification, object: UIApplication.sharedApplication())
Put in viewDidDissapear or deinit:
NSNotificationCenter.defaultCenter().removeObserver(self)
Swift 5.5:
NotificationCenter.default.addObserver(
self,
selector: #selector(yourFunction),
name: UIApplication.willEnterForegroundNotification,
object: UIApplication.shared
)
And:
deinit {
NotificationCenter.default.removeObserver(self)
}
I use Parse to save data and every time I add new data to server,TableView doesn't refresh and get new data
Is any way to refresh TableView except pull refresh ?
First of all Add Observer method which will notify when you.
NotificationCenter.default.post(name: Notification.Name("ReloadTableData"), object: nil)
Register that observer method in your view controller on which tableview you used.
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("ReloadTableData"), object: nil)
and create one function and reload your tableview
This might by your possible solutions for reloading without pull to refresh.
You can use this:
self.tableView.reloadData()
Whenever the user get back to the app or opens the app.
You can add in in the method
applicationWillEnterForeground
If the user is still in the app while the updates are being performed, then use push notification. In the method
appDidReceiveRemoteNotification
reload the data. You have to register for remote notification and all the process before you receive any push notification, but that is another issue.
first of all Adding refresh control to the tableview. So add the below code in ViewDidLoad.
let refresh = UIRefreshControl()
refresh.tintColor = UIColor.redColor()
refresh.attributedTitle = NSAttributedString(string:"Loading..!!", attributes: [NSForegroundColorAttributeName: UIColor.redColor()])
refresh.addTarget(self, action: "handleRefresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresh)
self.tableView.sendSubviewToBack(refresh)
Now Calling the method when you Pull-To-refresh Tableview.
func handleRefresh(refreshControl : UIRefreshControl){
self.tableView.reloadData()
refreshControl.endRefreshing()
}
Refresh Control :
Implement a push notification or use LiveQuery on parse-server.
LiveQuery allows you to subscribe to a Parse.Query you are interested in. Once subscribed, the server will notify clients whenever a Parse.Object that matches the Parse.Query is created or updated, in real-time.
LiveQuery is already support IOS.
for more detail see the hyperLink.
https://github.com/ParsePlatform/parse-server
https://github.com/ParsePlatform/parse-server/wiki/Parse-LiveQuery
https://github.com/ParsePlatform/ParseLiveQuery-iOS-OSX
I create a UILocationNotification with two action button one call sleep and wake up now. So once the user sees the notification if they pressed wake up now the app will launch and execute some code for some reason the app launches then refuse to execute the codes.
FYI : The code for the UILocalNotification were implement and they are working, the only problem is when I pressed the wake up now button.
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if notification.category == "options" {
if identifier == "Sleep"{
println("sleep more lazy bumm")
}
else if identifier == "wakeup"{
var object = ViewController()
object.wakeupnow()
}
}
Second Approach I took but it still not working
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if notification.category == "options" {
if identifier == "Sleep"{
println("sleep more lazy bumm")
}
else if identifier == "wakeup"{
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("wake"), name: UIApplicationWillEnterForegroundNotification, object: nil)
}
}
fun wake(){
var alertview = UIAlertView()
alert.message = "Good job you are up now, so lets get to work"
alert.addButtonWithTitle("ok")
alert.cancelButtonIndex = 0
alert.show()
}
Remember that application:handleActionWithIdentifer:forLocalNotification:completionHandler: gets called in a background thread. If you're doing anything in the UI you'll need to do it on the main queue.
Also, you have to call the completionHandler block as soon as you can, or the system will kill your app.
Please see the Apple documentation about this: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/#//apple_ref/occ/intfm/UIApplicationDelegate/application:handleActionWithIdentifier:forLocalNotification:completionHandler:
Also, in your first example you are instantiating a view controller and calling a function on it but you aren't actually presenting the view controller - what do you want to happen with that view controller? You'll need to do something to make it appear, which will depend on how your app is structured. You may want to present it modally over your root navigation controller, for example. Or maybe you mean to be calling that function on your already-existing ViewController, in which case you need to keep a reference to it somewhere instead of instantiating a new one when the notification action is triggered.
In your second example, you are adding yourself as an observer to the NSNotificationCenter instead of actually posting a notification, so of course your function will never get called. If you want to take that approach, you need to call addObserver sometime earlier - in applicationDidFinishLaunching:, for example:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("wake"), name: "wakeup", object: nil)
Then, in your handleActionWithIdentifier: function, call:
NSNotificationCenter.defaultCenter().postNotificationName("wakeup", object: nil)
That should result in your wake function being called. You still have the problem of trying to show an alert view from a background thread, though, so you would need to wrap your call in a dispatch_async:
func wake(){
var alertview = UIAlertView()
alert.message = "Good job you are up now, so lets get to work"
alert.addButtonWithTitle("ok")
alert.cancelButtonIndex = 0
dispatch_async(dispatch_get_main_queue(),{
alert.show()
})
}
Incidentally, UIAlertView is deprecated and should be replaced by UIAlertController for iOS 8 and up.