setText in UIlabel after notification call has no effect - ios

i want update the text of my label every time i receive notification from nsmanageObjContext.
this is my code for add the observer:
- (IBAction)requestFotPhoto {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateLabel) name:NSManagedObjectContextDidSaveNotification
object:self.facebook.managedObjectContext];
and this is the method for update the label:
-(void)updateLabel
{
NSString *text = [NSString stringWithFormat:#"Downalad %i pictures",[Photo NumeberOfAllPhotosFromContext:self.facebook.managedObjectContext]];
dispatch_async(dispatch_get_main_queue(), ^{
//UIKIT method
NSLog(#"text %#",text);
[self.downlaodLabel setText:text];
});
}
i assume that updateLabel is execute in a another thread, so i execute the instructions for update the label on the main thread, but this code has no effect. where is the problem?
obviously the NSlog print the right message!
thanks!

In your situation you don't need to use dispatch_async, because notification handlers are run in the main thread. They are executed in a main loop on idle moments — sorry if I'm wrong with techincal words, english is not native for me.
And one more thing: you should't reference self from blocks, because self points to your block, and block points to self — they're not going to be released. If you really want to do it, you can read this question.

seems like:
your should move your NSNotificationCenter addObserver code, from your (IBAction)requestFotPhoto (seems is some button click event handler, which only run after user tapped) to viewDidLoad
shold like this:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateLabel) name:NSManagedObjectContextDidSaveNotification object:self.facebook.managedObjectContext];
}
and for noficacation handler, not use dispatch_async
should like this:
- (void)updateLabel:(NSNotification *) notification {
NSLog (#"updateLabel: notification=%#", notification);
if ([[notification name] isEqualToString: NSManagedObjectContextDidSaveNotification]) {
NSDictionary *passedInUserInfo = notification.userInfo;
NSString *yourText = [passedInUserInfo objectForKey:#"dataKey"];
//UIKIT method
NSLog(#"yourText=%#",yourText);
[self.downlaodLabel setText:yourText];
}
}
and somewhere else should send the text:
NSString *newText = #"someNewText";
NSDictionary *passedInfo = #{#"dataKey": newText};
[[NSNotificationCenter defaultCenter] postNotificationName:NSManagedObjectContextDidSaveNotification object: self userInfo:passedInfo];
for more detail pls refer another post answer

Related

Object parameter in method postNotification of NSNotificationCenter

In my iOS application, I am posting a NSNotification and catching it in one of my UIView in main thread. I want to pass extra information along with the notification. I was using userInfo dictionary of NSNotification for that.
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotifyValueComputedFromJS" object:self userInfo:#{#"notificationKey":key,#"notificationValue":value,#"notificationColor":color,#"notificationTimeStamp":time}];
key, value, color and time are local variables which contains the value I need to pass. In UIView I am adding observer for this notification and I am using notification.userInfo to get these data
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"NotifyValueComputedFromJS" object:nil];
-(void)receiveNotification:(NSNotification *)notification
{
if ([notification.userInfo valueForKey:#"notificationKey"]!=nil && [[notification.userInfo valueForKey:#"notificationKey"] isEqualToString:self.notificationKey] && [notification.userInfo valueForKey:#"notificationValue"]!=nil) {
[self updateLabelWithValue:[notification.userInfo valueForKey:#"notificationValue"]];
}
}
The frequency in which this notification is posted is 4 times in one second. I am doing some animations also in main thread. The problem I am facing here is my UI is lagging. UI will respond to scroll events or touch events with huge delay(I have faced a delay of even 1 to 2 seconds). After some research I came to know that NSDictionary is bulky and will cause lag if used in main thread. Is there any other way I can pass my data through NSNotification?
I have tried out another way. I have created a custom NSObject class to save the data I want and I am passing it as the object parameter of postNotification method.
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotifyValueComputedFromJS" object:customDataObject userInfo:nil];
Here customDataObject is an instance of my custom NSObject class. I know the parameter is meant to be the sender of notification(usually it will be self). Is it a wrong approach if I am sending a custom object as parameter?
As BobDave mentioned, the key is to send the notification on some thread other than the main UI thread. This can be accomplished with dispatch_async, or with a queue.
The typical pattern for this behavior is sender:
-(void)sendDataToObserver {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotifyValueComputedFromJS" object:customDataObject userInfo:userInfo:#{#"notificationKey":key,#"notificationValue":value,#"notificationColor":color,#"notificationTimeStamp":time}];
});
}
And receiver (NOTE: weak self because retain cycles):
-(void)addObserver {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"NotifyValueComputedFromJS" object:nil];
}
-(void)receiveNotification:(NSNotification *)notification {
if ([notification.userInfo valueForKey:#"notificationKey"]!=nil && [[notification.userInfo valueForKey:#"notificationKey"] isEqualToString:self.notificationKey] && [notification.userInfo valueForKey:#"notificationValue"]!=nil) {
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateLabelWithValue:[notification.userInfo valueForKey:#"notificationValue"]];
});
}
}
Maybe you could use - addObserverForName:object:queue:usingBlock:
and use a non-main queue to execute the block in order to reduce the lag. Also, shouldn't the observer be added in a UIViewController, not a UIView?

View doesn't appear if displayed in response to a notification but does otherwise

I have a view I want to display on a certain event. My view controller is listening for a broadcast notification sent by the model and it attempts to display the view when it receives the broadcast.
However the view is not appearing. BUT if I run the exact same view code from elsewhere within the View Controller then it will be displayed. Here's some code from the VC to illustrate:
- (void) displayRequestDialog
{
MyView *view = (MyView*)[[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
view.backgroundColor = [UIColor lightGrayColor];
view.center = self.view.window.center;
view.alpha = 1.0;
[self.view addSubview:view];
}
- (void) requestReceived: (NSNotification*) notification
{
[self displayRequestDialog];
}
When the above code is run the view does not appear. However if I add the call to displayRequestDialog elsewhere, for example to viewDidAppear:
- (void) viewDidAppear
{
[self displayRequestDialog];
}
Then it is displayed.
My question therefore obviously is why can I get the view to successfully appear if I call displayRequestDialog from viewDidLoad, but it will not display if called from within requestReceived?
(Note that I am not calling requestReceived prematurely before the view controller / its view has loaded and displayed)
At first I was posting the notification like this:
[[NSNotificationCenter defaultCenter] postNotificationName: kMyRequestReceived
object: self
userInfo: dictionary];
Then I tried this:
NSNotification *notification = [NSNotification notificationWithName:kMyRequestReceived object:self userInfo:dictionary];
NSNotificationQueue *queue = [NSNotificationQueue defaultQueue];
[queue enqueueNotification:notification postingStyle:NSPostWhenIdle];
Then I tried this:
dispatch_async(dispatch_get_main_queue(),^{
[[NSNotificationCenter defaultCenter] postNotificationName: kMyRequestReceived
object: self
userInfo: dictionary];
});
Then I tried this:
[self performSelectorOnMainThread:#selector(postNotificationOnMainThread:) withObject:dictionary waitUntilDone:NO];
- (void) postNotificationOnMainThread: (NSDictionary*) dict
{
[[NSNotificationCenter defaultCenter] postNotificationName: kMyRequestReceived
object: self
userInfo: dict];
}
And I have tried invoking displayRequestDialog like this:
dispatch_async(dispatch_get_main_queue(),^{
[self displayRequestDialog];
});
I have found the cause of the view not displaying - the frame's origin is getting negative values when invoked via the notification code but positive values when invoked otherwise and thus was being displayed off the screen.
No idea why there should be a difference however.
You are not listening for the notification. Do so like this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(displayRequestDialog) name:kMyRequestReceived object:nil];
As far as we cannot see the code you use to register your controller to receive notifications I would recommend you to use the observer registration method which enforce getting notifications on the main thread "for free"
[[NSNotificationCenter defaultCenter] addObserverForName:#"Notification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(#"Handle notification on the main thread");
}];

How to check if notification is called then do not call method

I have two methods in viewDidLoad of the app and I want that if the notification method is called then the other method should not be called.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(actionNotificationDataA:)
name:#"reloadDataActivity"
object:nil];
Below is the other method. I want that if the notification method is not called, then this method should be called:
[NSThread detachNewThreadSelector:#selector(allData:) toTarget:self withObject:nil];
Otherwise, this method shouldn't be called.
First one will get called only when post that notification somewhere. But the second will detach the new thread suddenly when the code runs. That may create a problem look at it.
For an idea to your requirement:
Keep a BOOL with default to NO.
Then in the both methods check if the boolValue is NO, then run the code only if boolValue is NO and change the boolValue to YES.
Put BOOL isNotifCall; in your .h file.
In starting of viewDidLoad Method, give NO to isNotifCall, such like,
- (void)viewDidLoad
{
[super viewDidLoad];
isNotifCall = NO;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(actionNotificationDataA:)
name:#"reloadDataActivity"
object:nil];
[NSThread detachNewThreadSelector:#selector(allData:) toTarget:self withObject:nil];
}
Method of your NSThread (I don't know about parameter so i take id)
-(void)actionNotificationDataA:(id)Sender
{
isNotifCall = YES;
.
.
.
/// your Stuuf;
}
Method of your notification (I don't know about parameter so i take id)
-(void) allData:(id)Sender
{
if(!isNotifCall)
{
/// your allData method's Stuuf;
}
}

Notification Center gets called but value of UILabel is not updated in IOS

I am using push notifications in my code and whenever a notification comes, I want to update the value of a label in another ViewController.
My code in AppDelegate is:
- (void)addMessageFromRemoteNotification:(NSDictionary*)userInfo updateUI:(BOOL)updateUI
{
NSLog(#"Notification arrived");
//[mydeals setCode1_id:mydeals.code1_id withString:#"123456"];
mydeals=[[MyDealsViewController alloc]init];
NSDictionary* codeDetails=[[NSDictionary alloc] initWithObjectsAndKeys:#"123456",#"Code_id", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CodeArrived" object:self userInfo:codeDetails];
}
then in my other view controller I have this code:
#implementation MyDealsViewController
-(id) init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveCode:)
name:#"CodeArrived"
object:nil];
return self;
}
-(void) receiveCode:(NSNotification*)notification
{
NSLog(#"received Code: %#",notification.userInfo);
self.code1_id.text=[NSString stringWithFormat:#"%#",[[notification userInfo] valueForKey:#"Code_id"]];
}
the log is printed correctly but when I manually go into that screen I see the default value, like the label is not updated at all. What should I do?
You have to make sure that when you "manually go" to MyDealsViewController, whatever how you do it, it got to be the same instance of MyDealsViewController wich has been called receiveCode. Otherwise it's going to init with it's default values.
You might also try calling [self.code1_id setNeedsLayout];

Problems with NSNotificationCenter and UIPickerView

I hope I have better luck with someone helping me on this one:
I have a UIPickerView where a user makes a selection and then presses a button. I can gladly obtain the users choice, as shown in my NSLog, and when this is done, I want to send a notification to another view controller that will show a label with the option selected. Well, although it seems everything is done right, somehow it does not work and the label stays intact. Here is the code:
Broadcaster:
if ([song isEqualToString:#"Something"] && [style isEqualToString:#"Other thing"])
{
NSLog (#"%#, %#", one, two);
[[NSNotificationCenter defaultCenter] postNotificationName:#"Test1" object:nil];
ReceiverViewController *receiver = [self.storyboard instantiateViewControllerWithIdentifier:#"Receiver"];
[self presentModalViewController:receiver animated:YES];
}
Observer:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification) name:#"Test1" object:nil];
}
return self;
}
-(void)receiveNotification:(NSNotification*)notification
{
if ([[notification name] isEqualToString:#"Test1"])
{
[label setText:#"Success!"];
NSLog (#"Successfully received the test notification!");
}
else
{
label.text = #"Whatever...";
}
}
I think you have a syntax error in your selector: #selector(receiveNotification). It should probably be #selector(receiveNotification:) with the colon since your method accepts the NSNotification *notification message. Without it, it's a different signature.
The issue is likely that the notification is sent (and therefore received) on a different thread than the main thread. Only on the main thread will you be able to update UI elements (like a label).
See my answer to this question for some insight into threads and NSNotifications.
Use something like:
NSLog(#"Code executing in Thread %#",[NSThread currentThread] );
to compare your main thread versus where your recieveNotifcation: method is being executed.
If it is the case that you are sending the notification out on a thread that is not the main thread, a solution may be to broadcast your nsnotifications out on the main thread like so:
//Call this to post a notification and are on a background thread
- (void) postmyNotification{
[self performSelectorOnMainThread:#selector(helperMethod:) withObject:Nil waitUntilDone:NO];
}
//Do not call this directly if you are running on a background thread.
- (void) helperMethod{
[[NSNotificationCenter defaultCenter] postNotificationName:#"SOMENAME" object:self];
}
If you only care about the label being updated on the main thread, you can perform that operation on the main thread using something similar to:
dispatch_sync(dispatch_get_main_queue(), ^(void){
[label setText:#"Success!"];
});
Hope that was helpful!

Resources