I used RNBlurModalView , but now I want to call a new function when RNBlurModalView
disappears.
How can I do that?
Incidentally there are three ways(may be more):
Way 1: Use this method to hide your RNBlurModalView object and use the Completion Handler block to call the function(you want to call) when it is hidden.
- (void)hideWithDuration:(CGFloat)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options completion:(void (^)(void))completion;
Way 2: You can listen for kRNBlurDidHidewNotification NSNotification to know whether the view has been hidden or not.
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(modalViewHides:)
name:kRNBlurDidHidewNotification
object:nil];
Way 3: Use Key-Value Observing on the isVisible property.
[modal addObserver:self forKeyPath:#"isVisible" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
Example:::
- (void)viewDidLoad
{
[super viewDidLoad];
RNBlurModalView *modal = [[RNBlurModalView alloc] initWithViewController:self title:#"Hello world!" message:#"Pur your message here."];
[modal show];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(modalViewHides)
name:kRNBlurDidHidewNotification
object:nil];
}
- (void)modalViewHides
{
// call your function
}
Related
This is my code.
Here create the observer to Notification called Example into ViewController
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
}
From viewDidLoad register my observer
- (void)viewDidLoad
{
[self addObserverExample];
}
In my second ViewController. When tapped a button excute this code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:self.dictKeys userInfo:nil];
The problem I have is that the notification is never executed.
Any idea.
Have created demo for NSNotificationCenter as per your question and it's working fine for me. Here it is the link of that code: NSNotificationCenter Demo
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverExample];
}
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
NSLog(#"%#",notification.userInfo);
}
- (IBAction)btnFireNotification:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:nil userInfo:#{#"key" : #"value"}];
}
I believe the problem you're having may be related to the fact that in your second view controller, you're passing self.dictKeys in the object parameter.
If you want to pass data via the NSNotificationCenter, you should use the userInfo parameter instead.
Darshan's example does this the correct way.
I am facing an issue with NSNotificationCenter.
I am not able to send message and receive message using NSNotificationCenter in latest ios 8.4 (XCode 6.4)
Please check the following code:
1) I want to send data using first view controller to another view.
so i have written the following code in first viewcontroller:
When user btn clicked method as following :
- (IBAction)btnClicked:(id)sender
{
[self postNotification];
[self performSegueWithIdentifier:#"asGo" sender:self];
}
-(void)postNotification{
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:self];
}
2) In Second view controller i have added observer in ViewWillApper as following :
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(eventListenerDidReceiveNotification:)
name:#"MyNotification"
object:nil];
}
-(void)eventListenerDidReceiveNotification:(NSNotification*)txt
{
NSLog(#"i got notfication:");
}
so eventListenerDidReceiveNotification is not called while come on view.
But i am not getting above log while i come on second vc with navigation
As others have noted, NSNotificationCenter doesn't work like a post office. It only delivers notifications if someone actually listens to them at the moment they arrived. This is the reason your eventListenerDidReceiveNotification method is not being called: you add an observer in viewWillAppear, which is called after the segue (I assume that you're using segues because of the performSegueWithIdentifier method in your code) is finished, so it's definitely called after postNotification has been called.
So, in order to pass data via NSNotificationCenter you have to add an observer before you post a notification.
The following code is completely useless and unnecessarily overcomplicated, you shouldn't do anything like that, but since you keep insisting on using a scheme like this, here you go:
//Didn't test this code. Didn't even compile it, to be honest, but it should be enough to get the idea.
NSString * const SOUselessNotificationName = #"MyUselessNotification";
#pragma mark - FIRST VC
#interface SOFirstVC : UIViewController
#end
#implementation SOFirstVC
NSString * const SOasGoSegueIdentifer = #"asGo";
- (IBAction)btnClicked:(id)sender {
[self performSegueWithIdentifier:SOasGoSegueIdentifer sender:self];
}
-(void)postNotification {
[[NSNotificationCenter defaultCenter] postNotificationName:SOUselessNotificationName object:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifer isEqualToString:SOasGoSegueIdentifer]) {
SOSecondVC *destinationVC = (SOSecondVC *)segue.destinationViewController;
[destinationVC registerToReceiveNotificationsFromObject:self];
[self postNotification];
}
}
#end
#pragma mark - SECOND VC
#interface SOSecondVC : UIViewController
-(void)registerToReceiveNotificationsFromObject:(id)object;
#end
#implementation SOSecondVC
-(void)registerToReceiveNotificationsFromObject:(id)object {
[[NSNotificationCenter defaultCenter] addObserver:self selector:(eventListenerDidReceiveUselessNotification:) name:SOUselessNotificationName object:object];
}
-(void)eventListenerDidReceiveUselessNotification:(NSNotification*)uselessNotification {
NSLog(#"I got a useless notfication! Yay!");
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#end
NSNotificationCenter basically has 3 steps
Adding Observer like [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(open:) name:#"OpenDetail" object:nil];
Posting Notification [[NSNotificationCenter defaultCenter] postNotificationName:#"OpenDetail" object:self];
Removing Observer [[NSNotificationCenter defaultCenter] removeObserver:self name:#"OpenDetail" object:nil];
I think you are posting your notification and then later adding observer while it's vie versa. You have to add observer first then post notification.
HTH
First you have to setup the data you want to send
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:#"aKey"];
Then you post it with the data like so:
[[NSNotificationCenter defaultCenter] postNotificationName: #"MyNotification" object:nil userInfo:userInfo];
And finally you read the data off the notification:
-(void)eventListenerDidReceiveNotification:(NSNotification*)notification
{
NSLog(#"i got notification:");
NSDictionary *userInfo = notification.userInfo;
NSString *myObject = [userInfo objectForKey:#"aKey"];
}
I have a view that observe values of itself on init like this :
[self addObserver:self forKeyPath:#"focusPointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"exposurePointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"paused" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"previewLayerGravity" options:0 context:kSRCameraViewObserverContext];
And on dealloc, observers are removed as they should be like this :
[self removeObserver:self forKeyPath:#"focusPointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"exposurePointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"paused"];
[self removeObserver:self forKeyPath:#"previewLayerGravity"];
But unless calling it twice (with or without context, doesn't change anything), I have a crash when the view is deallocated cause the value are still observed.
But I'm quite sure observers are added only once (since it's in init of object).
I just wonder if why it could be registered twice ? Or is it like by calling it twice, it let to the object to effectively remove observers ? If someone have any clue ?
init is the primary initializer of NSObjet that means init must be called in Apple's implementation of initWithCoder / initWithFrame with something like [super init];
so your sharedSetup is called twice
EDIT (thanks to And Ainu):
To be more specific, that's the init method of UIView which calls the initWithFrame method.
Its good practice if you use try catch every time you remove the observer.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
[[NSNotificationCenter defaultCenter] addObserverForName:#"LocationSelected" object:nil queue:[NSOperationQueue mainQueue] usingBlock: ^(NSNotification *not) {
//Someone posted the notification handle it here
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
}
One more thing you can do is instead of observing in init method replace the same in loadView or awakeFromNib method. Then it will not called twice.
I have next code:
#implementation SplashViewVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.splashView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Default.png"]];
self.activityIndicator.originY = 355.f;
[[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
NSInteger errorCode = [n.userInfo[#"errorCode"] integerValue];
[self.activityIndicator stopAnimating];
if (errorCode == ERROR_CODE_NO_CONNECTION) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Some problem with server" delegate:self cancelButtonTitle:#"try again" otherButtonTitles:nil];
[alertView show];
} else if (errorCode == 0) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[self downloadData];
}
- (void)downloadData
{
[self.activityIndicator startAnimating];
[[Server sharedServer] getMovieData];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self downloadData];
}
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super viewDidDisappear:animated];
}
#end
So I put breakpoints in begin of viewDidLoad method, in viewDidDisappear. When I launch app that first go to viewDidload, after downloading it is go to viewDidDisappear.
But during my app I again download data and post notification: NSDownloadComplete. And in this VC it is work, but I removed later using:
[[NSNotificationCenter defaultCenter] removeObserver:self]
This VC use viewDidLoad once in the beginning & can not again addObserver.
What is wrong?
EDIT
I try put addObserver method to viewWillAppear or viewWillDisappear - no results.
I add NSLog(#"addObserver"); before
[[NSNotificationCenter defaultCenter] addObserverForName...
in viewDidLoad
and write
- (void)viewDidDisappear:(BOOL)animated
{
NSLog(#"removeObserver");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super viewDidDisappear:animated];
}
In log I see:
2013-06-10 14:32:05.646 myApp[9390:c07] addObserver
2013-06-10 14:32:06.780 myApp[9390:c07] removeObserver
What wrong?
EDIT 2
you can see that observer must be removed but it again run block in addObserver method
Apart from add/remove observer calls not properly being balanced, at noted in the other answers, there is another problem.
Your code to remove the observer is wrong. For a block-based observer, the return value of addObserver must be given as argument to removeObserver. So you should add a property
#property(nonatomic, strong) id observer;
to the class. Then you add the observer with
self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
// ...
}];
and remove it with
[[NSNotificationCenter defaultCenter] removeObserver:self.observer];
What e1985 is trying to expose is that your addObserver and removeObserver calls are not properly balanced. viewDidLoad is called only once after the VC initialization, but viewDidDisappear is called each time the view controller is moved off screen.
To resolve your issue you must balance your addObserver and removeObserver calls, either by making them in viewDidLoad and the other in dealloc, or - as e1985 suggested - in viewDidAppear: and viewDidDisappear:.
EDIT: Ok, so your problem comes from the fact that you are using addObserverForName:object:queue:usingBlock: which do not register self as observer (as addObserver:selector:name:object: would do if you pass self as first argument).
So in your case, [[NSNotificationCenter defaultCenter] removeObserver:self]; does nothing because self is not an observer. You should instead call removeObserver: on the return value of addObserverForName:object:queue:usingBlock:, as shown in the doc:
Return Value
An opaque object to act as the observer.
So your code should looks something like:
// header file .h
#interface SplashViewVC : UIViewController
#property (strong, nonatomic) id downloadCompleteObserver;
#end
// implementation file .m
#implementation SplashViewVC
- (void)viewDidLoad
{
[super viewDidLoad];
// [...] snip
self.downloadCompleteObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
NSInteger errorCode = [n.userInfo[#"errorCode"] integerValue];
[self.activityIndicator stopAnimating];
if (errorCode == ERROR_CODE_NO_CONNECTION) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Some problem with server" delegate:self cancelButtonTitle:#"try again" otherButtonTitles:nil];
[alertView show];
} else if (errorCode == 0) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[self downloadData];
}
// [...] snip
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self.downloadCompleteObserver];
[super dealloc];
}
#end
The pattern you are using is not correct. You should add the observer in viewDidAppear: and remove it in viewDidDisappear:.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to tell when controller has resumed from background?
How to refresh View after user enters applicationWillEnterForeground?
I want to complete recall for example HomeViewController.
I have and update function in HomeViewController and I want when user enters to call update function and reload table data.
Any class can register to UIApplicationWillEnterForegroundNotification, and react accordingly. It's not reserved to the app delegate, and helps for better separation of source code.
Create a viewDidLoad method like this for your HomeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(yourUpdateMethodGoesHere:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
// Don't forget to remove the observer in your dealloc method.
// Otherwise it will stay retained by the [NSNotificationCenter defaultCenter]...
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
If your ViewController is a tableViewController your could also directly call the reload data function:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:[self tableView]
selector:#selector(reloadData)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Or you could use a block:
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
[[self tableView] reloadData];
}];
You could declare a property in your app delegate class that would point to the HomeViewController object. Then you can call your update function in applicationWillEnterForeground.