In iOS 9 the following code for detecting a notification does not fire the selector method. In previous versions (e.g. 8.4) it's running fine. Does anyone know why?
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(yourMethod)
name:UIApplicationDidBecomeActiveNotification
object:nil];
- (void)yourMethod {NSLog(#"aaaaaaa");}
This link as below maybe help your problem.
Foundation Release Notes for OS X v10.11
Use "addObserverForName" instead of "addObserver".
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * Nonnull note) {
[self yourMethod];
}];
It will be work.
I hade the same problem and for me it worked to move the addObserver code to awakeFromNib. Another solution could be to add a delay to the addObserver as in the example below:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
});
While doing some tests, I noted that the notification is actually triggered, albeit not at launch time (or at least too early to be caught by your observer) (on the simulator only).
Try pulling the notification center down and up or the control center up and down, and you'll see your method will actually be called.
I'd suggest maybe calling your method manually on iOS 9, when your app starts?
On a real device, the method is called just as on iOS 8.
Edit: after further investigation, it seems the notification is actually not triggered every time on devices :/
I've also bumped into this problem and adding the observer with a delay didn't solve it in my case. Managed to get rid of it by calling the method directly in AppDelegate and from the main queue, without a delay.
Swift:
func applicationDidBecomeActive(application: UIApplication) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
yourMethod()
}
}
I had the exact same issue only on real devices running iOS 9.0 and up.
I ended up defining my own notification:(this define should be globally available, constants.h or alike)
#define myAppBecameActiveNotif #"Tito, your app is active"
Then, in your AppDelegate implementation (AppDelegate.m most of the cases) you implement applicationDidBecomeActive delegate method:
- (void)applicationDidBecomeActive:(UIApplication *)application {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:myAppBecameActiveNotif
object:nil];
});
}
(Just delay the dispatch of your notification a bit, to let your components come to life)
Now, in the class you'd like to be notified the app became active you do
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(whatToDoWhenAppActive:)
name:myAppBecameActiveNotif
object:nil];
Working good now. You'll see you cannot feel this 500ms delay...
I do notification register like that.
[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(yourMethod:) name:UIApplicationDidBecomeActiveNotification object:nil];
Write Method like that.
- (void)yourMethod:(NSNotification *)notification
{
NSLog(#"aaaaaaa");
}
Also you need to NSLog in AppDelegate.m and see log in console.
-(void)applicationDidBecomeActive:(UIApplication *)application{
NSLog(#"applicationDidBecomeActive");
}
Related
I came across a strange problem when handling a NSNotification iOS 13
// Adding the observer in viewWillAppear
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
NSLog(#"Adding observer");
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification) name:#"someNotification" object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
...
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"someNotification" object:nil];
NSLog(#"Removed observer");
}
- (void)handleNotification {
NSLog(#"Handle notification");
}
I have double checked that the notification is posted only once. There is only one place in the app where someNotification is posted and a breakpoint and NSLog confirms, that this code is only executed once.
Result in iOS 12 and below:
Adding observer
Handle notification
Result in iOS 13 and below:
Adding observer
Handle notification
Handle notification
So in iOS 13 the observer is called twice while the exact same code in iOS 12 and blow is only called once.
My first guess was, that for some reason in iOS 13 viewWillAppear is called twice that thus the observer is added twice. However, in this case the NSLog output Adding Observer should also appear twice, shouldn't it?
BUT: The problem can be solved by removing the observer in viewWillAppear before adding it. This makes sure, that the observer is added only once:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
NSLog(#"Adding observer");
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"someNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification) name:#"someNotification" object:nil];
}
So, since this solves the problem the observer obviously is added twice in viewWillAppear. But why?
Why is viewWillAppear called twice in iOS 13? And even more important: How is it possible, that it is called twice but the NSLog output Adding Observer appears only once?
I have two class which uses NSNotification to communicate with each other.
Currently, i have an issue with notification being fired twice, i've double/triple/even more checked that observer is not added more then 1 time, notification not being posted twice, did global search on my project for same notification.
My code is like below
Added Notification Observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:notification_deleteMediaFromGallery object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationReceiver:) name:notification_deleteMediaFromGallery object:nil];
Notification Receiver
- (void)notificationReceiver:(NSNotification*)notification {
if ([notification.name isEqualToString:notification_deleteMediaFromGallery]) {
if ([[notification.userInfo objectForKey:#"kind"] integerValue]==GalleryKindPhoto) {
//My statements
}
else if ([[notification.userInfo objectForKey:#"kind"] integerValue]==GalleryKindVideo) {
//My statements
}
}
}
Post Notification
dispatch_async(dispatch_get_main_queue(), ^{
[_browser reloadData];
[[NSNotificationCenter defaultCenter] postNotificationName:notification_deleteMediaFromGallery object:nil userInfo:#{#"index":#(_browser.currentIndex), #"kind":#(self.kind), #"function":[NSString stringWithFormat:#"%s",__PRETTY_FUNCTION__]}];
});
I have also tried this solution by EmptyStack but not get it to work.
I'll be very thankful to you if you could help me solve this issue.
Thanks.
Edit
NOTE
I've added observer in my viewdidload, and cant add/remove observer from viewwillappera/viewwillappear or viewdidappear/viewdiddisappear because the next viewcontroller which will be pushed on current viewcontroller will post notifications
I think you need to write dealloc method in your view controller. And remove All Notification observer in dealloc method,
- (void)dealloc
{
// Deregister observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:notification_deleteMediaFromGallery object:nil];
}
Hi please make sure your method is not calling two time from where you are firing notification.
& please add your notification observer in viewWillDisappear method.
I have the following code within AppDelegate. The purpose being to create a couple of observers, and then call some code. Once that code completes it then posts a notification, and the observer should then remove both observers and call the completion handler.
My issue is that it appears that the observers are not being removed as I expected. The notification is posted, and the NSLog entry is written to console, so I know that the observer is working. However, on the second time of calling, the NSLog is called twice, third time three times etc.
My thoughts are that this is to do with the removal being within the block of code that is running from the observer, however, I am unsure how I can resolve this (if indeed this is what the issue is).
Could someone be so kind as to explain how I can achieve this?
Thanks.
-(void) application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
[[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNewData" object:nil
queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNewData"
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNoData"
object:nil];
// Post completion
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"Background fetch completed... New Data");
}];
[[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNoData" object:nil
queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNoData"
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNewData"
object:nil];
//post completion
completionHandler(UIBackgroundFetchResultNoData);
NSLog(#"Background fetch completed... No New Data");
}];
GetDetails *getDetails = [[GetDetails alloc] init];
[getDetails backgroundRefresh];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
You are not registering self as an object. Moreover, when the block is pushed onto the stack by addObserverForName: the method has not yet returned so the notification is nil.
Make a global object using block, eg
__block __weak id notification;
then,
notification = [[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNewData" object:nil queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:notification];
}];
My thoughts are that this is to do with the removal being within the
block of code that is running from the observer, however, I am unsure
how I can resolve this (if indeed this is what the issue is).
Could someone be so kind as to explain how I can achieve this?
Certainly.
You can easily test your theory by not using the addObserverForName:object:queue:usingBlock: method and instead using the addObserver:selector:name:object: method, where the selector is the name of a function you call instead of using a block.
Simply use the API guide for NSNotificationCenter for details about these methods, or in general, since you question was about what other method you could use that does not require a block statement, consulting the API is the first place to check for alternative tools within the class.
How to use UIApplicationDidBecomeActiveNotification?
Should I declare it in viewDidLoad or viewWillAppear to reload data when coming from background to foreground.
Does UIApplicationDidBecomeActiveNotification gets called only when app comes from background to foreground?
Please help.
Thanks.
Sometimes it is useful to have a listener of UIApplicationDidBecomeActiveNotification when you need to make some action in your view controller on wake up from background (in case you entered to background with this view controller on-screen). In such wake up viewWillAppear will not be triggered!
Example of use:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(someMethod) name:UIApplicationDidBecomeActiveNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
- (void)someMethod
{
<YOUR CODE AT WAKE UP FROM BACKGROUND>
}
Of course, you can also implement all you need at your app delegate class life cycle.
You get this notification if your app was interrupted by a phone call or push notification. Generally, if your application is getting active on screen after interruption.
You can register any class, that is loaded in memory by the moment application will become active as observer to this notification.
Use following code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(someMethod:)
name:UIApplicationDidBecomeActiveNotification object:nil];
Use someMethod to handle this notification. And don't forget to remove this class as observer in dealloc:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationDidBecomeActiveNotification
object:nil];
The OP asked about system notifications fired when the app is backgrounded and then foregrounded again. The Notification designed to handle this situation is the UIApplicationDidEnterBackgroundNotification and UIApplicationWillEnterForegroundNotification. If you want a notification that fires for a wider range of situations, such as when you have a system notification, take a phone call, a SMS comes in, or you slide up the control pane, as well as being backgrounded then you will want the UIApplicationWillResignActiveNotification and UIApplicationDidBecomeActiveNotification. It's important to recognize that these are different, since you might only need to react if your app is backgrounded, and not for other scenarios.
I'm trying to get NSNotifications to work. At this moment, without success.
In my appDelegate.m file I have:
[[NSNotificationCenter defaultCenter] postNotificationName:#"first" object:nil];
In my mainViewController.m, in the viewDidLoad method I have
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(firstRun)name:#"first" object:nil];
and created a method (in mainViewController.m as well):
-(void) firstRun:(NSNotification *) notification
{
NSLog(#"This works!");
}
However, I do not see any output in the log when running the app.
What is wrong with my code? Please advise.
Wrong selector, should be:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(firstRun:)name:#"first" object:nil];
The answer above, which points out that you had used the wrong selector in the observer method, is definitely a problem.
Another thing that you should check is that you add the observer before the notification is posted. Notifications are synchronous. When posted, they will only be recognized by observers that are already registered.
I recommend that you set a breakpoint on the line where you post the notification, and also on the line where you add the observer, and see which gets hit first.