Delay NSNotification until another is complete - ios

I have a global function that downloads JSON data from a server and parses it. It normally takes about 5 seconds to run, so we do this in the background and then send out a notification, kNotificationDownloadSuccessful.
One of the several observers of the notification is a MapView, who re-draws annotations based on the data it received. This, obviously, has to happen after it's told the data is ready by receiving kNotificationDownloadSuccessful.
In some cases I want to re-center the map on the new data. This, obviously, cannot happen until the map has completed drawing annotations. So I implemented a second notification, kNotificationMapLocationSet, which the callers fire if they want this to occur, and the map listens for it.
Now the problem... kNotificationMapLocationSet is being received before kNotificationDownloadSuccessful, which makes perfect sense really. The Map can't simply re-post it, or just call it's local re-center method, because it doesn't know if the recenter is required.
I thought about having the kNotificationMapLocationSet set a flag in the Map, and then have the handler on kNotificationDownloadSuccessful look at it and recenter if desired. But then that would fail in the case where the messages are received in their current order.
So is there a way to order the notifications? IE, delay this one until that one fires?

I believe you can use addObserver to check when the NSNotification is done. Let me know if this works:
NotificationCenter defaultCenter] addObserver:self
selector:#selector(callNextNotification:) name:#"notificationSent" object:nil];
It looks like you subclassed NSNotification, but this should still work.

Related

Remove previously posted notification

Posting notifications from the NSNotificationCenter on the certain button click event Hence When I have rapid button events The notification is being called that many times leads to the many problems. I want to cancel the previous posted notification when rapid events happening. How to do with below code.
func buttonClick() {
// I want to cancel the previous Event here
NSNotificationCenter.defaultCenter().postNotificationName("Event", object: self)
}
UPDATE:
Let me explain clearly what I want actually I have one observer method when a button click is happened from that I want to post the some notifications to control some UI elements like changing the button image. The problem is When I hit the button rapidly observer getting called many times as well my notifications being posted on the same count hence UI is blinking I can't have control on the Observer on the button click event I have only control over the posted event from my side.
Any help much appreciated.
NSNotificationCenter.post() is synchronous. It does not return until all the observers have performed their actions. So there is no way to cancel it; there is no queue.
If you are generating a lot of notifications very close to each other (especially within the same run-loop cycle), you can coalesce them using NSNotificationQueue with enqueueNotification. Generally something like:
NSNotificationQueue.defaultQueue().enqueNotification(note, postingStyle: .whenIdle)
That said, if this is tied to a button click (a human interaction), then the notifications are likely very far apart in computer terms. Half a second is an eternity in computer terms. If that's the case, you're likely better-off controlling this first at the UI, by disabling the button until you're willing to accept another click (for example with button.enabled = false).
It is possible to write a wrapper that coalesces operations over any arbitrary period, but this is likely to be confusing in your case, because the user will be able to click something that the system will ignore. If that's still what you want, I'll see if I can find an example of a coalescing trampoline (I've written them in ObjC, but I don't have a Swift example on hand).

iOS Swift: clear a specific type of notifications from NSNotificationCenter?

Is there a way to clear all Notifications that has notificationName = AVSystemController_SystemVolumeDidChangeNotification from the NSNotificationCenter.defaultCenter()?
I looked into many questions and I found a way to clear local notifications (UILocalNotification not NSNotifications) using `cancelLocalNotification(notification). I also found a way to clear ALL notifications from the notification center. I also looked into notification center documentation but didn't find something about that.
Note: Here is why I want it: I want to add an observer for volume change (when the user presses on the volume buttons) and I use (AVSystemController_SystemVolumeDidChangeNotification).
However, when I add it, I have to wait half a second (dispatch_after) to avoid any accumulating button presses from the user that happened right before (or while) adding the observer. In other words, the observer finds "old" notifications that were in the notification center before I tell it to start "observing".
So, I don't want to block main thread. Instead, I want to clear all the volume change notifications before I add the observer (this way I can be sure that no 'old' notification will trigger my actions).
I want to clear a specific type of notifications that has this notificationName.
Any ideas how to do it in Swift?

Settings Changed Notification In Subclass Of IASKAppSettingsViewController

I have a subclass of IASKAppSettingsViewController that I, of course, use to display and handle various events for the settings I present to the user.
In this subclass, I am trying to receive the notification that settings were changed by adding this line to -(void)viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(settingsChanged:) name:kIASKAppSettingChanged object:nil];
Problem is that the method, settingsChanged, is never being called. I figure that there is some other way of doing this or I am doing something wrong here. This procedure does work for me in other classes, so I assume there is something special about IASKAppSettingsViewController that is preventing this from working. Can someone point me in the right direction?
EDIT #1
Received a message from Future Tap via GitHub and he asked me to check the sample app. I did and the sample app does not use a subclass of IASKAppSettingsViewController. I have since added another addObserver and that is also not being called. I verified that both addObserver calls are being executed, so that is not the cause.
EDIT #2
It appears that something is terribly amiss in my app. I have multiple classes that observe this notification and they all use the same name for the method to be called (settingsChanged). When I Command-click the name of the method in one addObserver call, Xcode brings me to another class' settingsChanged method. This is probably what is causing some of my observer methods not to get called.
Working with Future Tap, we discovered that `IASKAppSettingsViewController' was removing all observers when the view disappeared. This was causing the observers that I set up to be removed and, thus, not be called. The code has been fixed and my problem is solved.

NSNotification not working from another class

Part of an app I'm working on involves putting a blank screen over the current content if the user becomes inactive. As such after x seconds a blank page view controller is opened:
(From within ViewController.m and triggered by detecting an NSNotification from ScreenBlank.m)
UIPageViewController *blankPage = [self.storyboard instantiateViewControllerWithIdentifier:#"BlankPageViewController"];
[self presentViewController:blankPage animated:YES completion:nil];
This blank screen is then removed when a user touches the screen (And thus confirms their activity), like so:
(From inside the touchesBegan callback of ViewController.m)
[self dismissViewControllerAnimated:YES completion:nil];
The problem I'm having, is that I now want to trigger removing this screen blanking elsewhere, such as when the user logs out. This is done by removing a card from a plugged in card-reader, and means that it is called from a separate class (And one that is instantiated from within ActionMgr.m).
The class in question (CardWatcher) is created like so:
CardWatcher *newInstance = [[CardWatcher alloc] init];
[newInstance StartCardChecker];
And that instance of CardWatcher issues a notification when the card is removed, like so:
[[NSNotificationCenter defaultCenter] postNotificationName:#"logout" object:nil];
This notification is then listened for in ViewController, and on being triggered, executes EXACTLY the same code as is used to blank the screenearlier:
[self dismissViewControllerAnimated:YES completion:nil];
By using logging, I have determined that the notification is being received fine, and is executing the dismissViewControllerAnimated code, but for some reason, said code is not actually dismissing the view controller.
The only reason I can think of, is that it is (In the long run) called form within an instance of a class, but even then it's being passed via an NSNotification, and so in my eyes its source should be irrelevant?
Any help would be much appreciated!
It sounds like the notification is not generated on the main thread and you are hence trying to dismiss the page from a secondary thread. Make sure that you are posting the notification on the main thread and not from secondary threads. When a notification triggers UI events, such as this one, the code that manipulates the UI is required to be executed on the main thread.
Delivering Notifications To Particular Threads
Regular notification centers deliver notifications on the thread in
which the notification was posted. Distributed notification centers
deliver notifications on the main thread. At times, you may require
notifications to be delivered on a particular thread that is
determined by you instead of the notification center. For example, if
an object running in a background thread is listening for
notifications from the user interface, such as a window closing, you
would like to receive the notifications in the background thread
instead of the main thread. In these cases, you must capture the
notifications as they are delivered on the default thread and redirect
them to the appropriate thread.
Just try the following code and let me know if it worked for you.
dispatch_async(dispatch_get_main_queue(),^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"logout" object:nil];
});

Recursive Notifications

My application is IOS application.
I have a scenario typical to the calendar iPad application, when the user goto to a date from a view, each views update itself and notify others. The problem is that notifications between views never ends.
I am using the NSNotificationCenter
[[NSNotificationCenter defaultCenter] postNotificationName:SelectedDateChangedNotification object:self userInfo:nil];
I would like to explore some ideas of how effectively implement this scenario.
Thanks
You need to have two ways of updating each of your views. The first way is when the user updates it and the second way when it gets updated by a different view. The first way sends notifications to the other views and the second way does not. From an implementation standpoint, the first way would just be a wrapper around the second way which first notifies the other views.

Resources