Sending a notification when the operation has been completed in one class? - iphone

I have two classes, Class A and Class B.
Class A has a method
-(void)methodA:(id)sender
{
}
and Class B has a method
-(void)methodB:(id)sender
{
}
Now i have some work is happening in methodA ,So once it is completed i want to send a notification from methodA: to methodB: So i can do some operation on the basis of notification.
So how can i do this? Can anybody guide me as i am new to obj-c?

Use delegate. Simple code from wiki: visit http://en.wikipedia.org/wiki/Delegation_pattern
A delegate is an object whose objects are (generally) called to handle or respond to specific events or actions.
You must "tell" an object which accepts a delegate that you want to be the delegate. This is done by calling [object setDelegate:self]; or setting object.delegate = self; in your code.
The object acting as the delegate should implement the specified delegate methods. The object often defines methods either in a protocol, or on NSObject via a category as default/empty methods, or both. (The formal protocol approach is probably cleaner, especially now that Objective-C 2.0 supports optional protocol methods.)
When a relevant event occurs, the calling object checks to see if the delegate implements the matching method (using -respondsToSelector:) and calls that method if it does. The delegate then has control to do whatever it must to respond before returning control to the caller.

Register an Observer in Class B like :
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(method:) name:#"notificationName" object:nil];
And Post the notification from Class A like:
[NSNotificationCenter defaultCenter] postNotificationName:#"notificationname" object:nil];
Remove the Observer in your class B, when it is deallocated like
[[NSNotificationCenter defaultCenter]removeObserver:self];

Easiest way.
In Class B's -(id)initWithNibName: Bundle: you will need to add in registering for NSNotifications.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(methodB:)
name:#"methodAFinished"
object:nil];
}
return self;
}
And then you need to do the following in the Class A methodA: function.
- (void)methodA:(id)sender {
// Once you have completed your actions do the following
[[NSNotificationCenter defaultCenter] postNotificationName:#"methodAFinished" object:nil];
}
- (void)methodB:(id)sender {
// This will then be called in the other class, do whatever is needed in here.
}
Hope that works for you!
Also, don't forget, in Class B's -(void)viewDidDisappear:animated function, you need to unregister for the notifications.
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
That should accomplish what you're asking for. Please add to your question if this isn't what you're working or comment below and I can rectify my answer.

Related

NSNotificationCenter postNotificationName exec_badaccess

I have a view controller, when it's dissming with completion, I post a notfication, and in a subview which contained in another view controller, has added as a oberserve. But, when it tries to execute post notificaiton methode, exec_bad_access happend. what's wrong? The codes are:
BrandListByIdViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *bid = self.brands[indexPath.row][#"id"];
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"SelectedBrandId" object:nil];
}];
}
SearchNewProduct.h
#interface SearchNewProduct : UIView
#end
SearchNewProduct.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didSelectedBrandId::) name:#"SelectedBrandId" object:nil];
}
}
- (void)didSelectedBrandId:(NSNotification *)notif{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
Even I get rid of the userInfo, still bad access. I created a similar situation in another new project, it works fine.
I didn't realize that you were dealing with a UIView and not a UIViewController (should have read your question better). I think what is happening is that the View is receiving notifications even after being released. Make sure to call dealloc in your UIView and remove itself as an observer:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Also, put an NSLog in that UIView's initWithFrame method to see if it is being called more than once.
This question is very similar:
ios notifications to "dead" objects
Not sure if this is the reason, but when you add your view to the notification center, your selector is wrong:
selector:#selector(didSelectedBrandId::)
There should only be one colon. The entire line should be:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didSelectedBrandId:) name:#"SelectedBrandId" object:nil];
Two colons indicates the method takes two arguments, but it only takes one.

How can my main view controller know when the web service call finished

Hi I have an web service based app that will interchange data with our server. Since I have a dedicated class doing my work, the main view controller will actually call the worker every time. The worker itself knows when the connection finished since it is a NSURLConnectionDelegate. However I need to inform the main view controller whenever the work is done. The worker is a delegate of main view controller so it knows when it need to start working. Please help me.
You should do the other way around.
First declare your worker object as a member of your main view controller(and of course, make it a property), then from you main view controller, you can just call [self.worker sendRequstToServer] to send the request.
Second, within your main view controller, wherever you initialize your work object, don't forget to put self = worker.delegate.
Third, declare a delegate method in your worker class, something like -(void)webServiceCallFinished(), and call [self.delegate webServiceCallFinished] in your worker's -connectionDidFinishLoading() (you might wanna do in -parserDidEndDocument() if you are using NSXMLParer to parse xml)
Last, you wanna declare your main view controller as the delegate of your worker class and implement -webServiceCallFinished().
Hope this helps.
You can do it in two ways:
Approach #1:
User Local notifications.
In the mainclass add an observer into LocalNotification Center in following way.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(jobDone) name:#"WORKERJOBOVER" object:nil];
And in the worker class when the job is done, post nofitication to fire the selector:
[[NSNotificationCenter defaultCenter] postNotificationName:#"WORKERJOBOVER" object:nil];
Approach #2:
You can create a protocol of your worker class and add a method in the protocol which you can call on the delegate when your job is done in worker.
WorkerClass.h
//WorkerClass.h
#protocol WorkerDelegate
#interface WorkerClass: NSObject
#property (nonatomic, assign) id<WorkerDelegate> delegate
- (void)JobInProcess;
#end
#protocol WorkerDelegate
- (void)MyJobIsDone;
#end
WorkerClass.m
//WorkerClass.m
#implementation WorkerClass
#synthesize delegate = _delegate;
- (void)JobInProcess
{
//When job over this will fire callback method in main class
[self.delegate MyJobIsDone];
}
MainClass.h
//MainClass.h
#import WorkerClass.h
#interface MainClass: NSObject <WorkerDelegate>
#end
MainClass.m
//MainClass.m
#implementation MainClass
- (void)MyJobIsDone
{
//Do whatever you like
}
#end
In viewDidLoad: of your main view controller, set it as a notification observer with [NSNotificationCenter defaultCenter]:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(webServiceContacted:) name:#"webServiceConnectionSuccessful" object:nil];
Then when your data was successfully interchanged with the server, post a notification within the network completion block:
[[NSNotificationCenter defaultCenter] postNotificationName:#"webServiceConnectionSuccessful" object:nil];
And webServiceContacted: could look like this:
-(void)webServiceContacted:(NSNotification *)note
{
//do stuff here
}
I would fire a notification from the background worker that you can listen for from your main view controller
In your View add the following when you want to listen.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(operationComplete:) name:#"operationComplete" object:nil];
In your background View notify that the event completed.
[[NSNotificationCenter defaultCenter] postNotificationName:#"operationComplete" object:nil];
Finally don't forget to remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self];

Can I Register a Class for NSNotifications? Can I use Class Methods with NSNotifications?

I'm working on a class for my iPhone app, and I'd like it to register for and be aware of application state changes (UIApplicationDidEnterBackgroundNotification, etc). Is there a way to register a class for notifications without having to keep an instantiated object in memory? I just want to have the appropriate notifications call the class to init, do some stuff, and then leave memory again.
Right now I have the following in the init method:
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleEnteredBackground)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
and this method elsewhere in the .m file of the class:
- (void) handleEnteredBackground {
NSLog(#"Entered Background"); }
I instantiate the class once under applicationDidLoad, but since I don't do anything with it I presume ARC kills the object from memory and the app crashes (without any useful error codes, mind you) when I go to close it. If I switch handleEnteredBackground to a class method with a "+" sign, I get invalid selector errors when I close the app.
The end goal is to instantiate a class once in the lifecycle of an app and have it be able to respond to app state changes without any additional code outside the class. Assume iOS 5 + Xcode 4.2+
The following should work:
[[NSNotificationCenter defaultCenter] addObserver: [self class]
selector: #selector(handleEnteredBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
The selector itself:
+ (void) handleEnteredBackground: (NSNotification *) notification
{
}
You don't have to unregister the observer, because the class object cannot be deallocated or otherwise destroyed. If you need to unregister the observer for other reasons, you can:
[[NSNotificationCenter defaultCenter] removeObserver: [self class]];
You should look into singletons.
You can easily create an object that lasts through the whole application lifecycle.
+ (id)sharedObserver
{
static dispatch_once_t once;
static YourObserverClass *sharedObserver = nil;
dispatch_once(&once, ^{
sharedObserver = [[self alloc] init];
});
return sharedObserver;
}
- (void)startObserving
{
// Add as observer here
}
Now you can call [[YourObserverClass sharedObserver] startObserving] and you don't have to worry about retaining it etc.

NSNotification only NSLog works

In my Class X I post a Notification like this:
[[NSNotificationCenter defaultCenter] addObserver:viewController
selector:#selector(doThis:)
name:#"myNotification"
object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification" object:nil];
In my Class Y I recieve it like this:
- (void) doThis: (NSNotification *) notification {
NSLog(#"It works.");
[uiTextView resignFirstResponder]; }
The console shows the NSLog message but my UITextView does not hide its keyboard.
(In e.g. viewDidLoad the resignFirstResponder/becomeFirstResponder works.)
Is there any special thing I need to do?
FWIW, in most, but not all, cases, observers should be added and removed by the observer itself, not by a separate object. (What happens if the observer goes away before the separate object, and fails to have the observer properly removed? Or vice-versa? It makes it all too easy to either leak observers or crash on notifications to deallocated objects.)
Anyhow, first thing's first: have you verified that uiTextView is not nil and points at the first responder? I rather suspect that uiTextView is not what you think it is.
As Conrad says, observers should be added and removed by themselves...
Use the best practice to define the name of the notifications as static constants like follows:
static NSString *const kMyNotification = #"myNotification";
Why? because there is a risk that both #"myNotification" might be two different objects and then the notificationName is different and you won't receive the notification. Since I always declare them as static constants I have never had issues with NSNotifications.
Then use it like this:
To register the observer
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(doThis:)
name: kMyNotification
object: nil];
To post the notification
[[NSNotificationCenter defaultCenter] postNotificationName: kMyNotification
object: nil];
To remove the observer:
[[NSNotificationCenter defaultCenter] removeObserver: self];

Can I watch an NSNotification from another class?

I'm trying to get my head around NSNotificationCenter. If I have something like this in my App Delegate:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(something:)
name:#"something"
object:nil];
-----
-(void)something:(NSNotification *) notification
{
// do something
}
Can I somehow watch this in another view controller? In my case, I'd like to watch it in a view controller with a table, and then reload the table when a notification is received. Is this possible?
Yes you can do it like this:
In class A : post the notification
[[NSNotificationCenter defaultCenter] postNotficationName:#"DataUpdated "object:self];
In class B : register first for the notification, and write a method to handle it.
You give the corresponding selector to the method.
//view did load
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleUpdatedData:) name:#"DataUpdated" object:nil];
-(void)handleUpdatedData:(NSNotification *)notification {
NSLog(#"recieved");
}
Yes you can that is the whole purpose of NSNotification, you just have to add the View Controller you want as an observer exactly the same way you did on your App Delegate, and it will receive the notification.
You can find more information here: Notification Programming
Of course it's possible, that's the whole point of notifications. Using addObserver:selector:name:object: is how you register to receive notifications (you should do this in your table view controller), and you can use postNotificationName:object:userInfo: to post a notification from any class.
Read Notofication Programming Topics for more info.
You can register to observe notifications in as many classes as you like. You simply need to "rinse and repeat". Include the code to register as an observer in your view controller (perhaps in viewWillAppear:) and then reload the tableView from your method:
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(something:) name:#"something" object:nil];
}
-(void)something:(NSNotification *) notification
{
[self.tableView reloadData];
}
It's also a good idea to de-register the view controller once you no longer need the notifications:
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
You should just add that as an Observer and give a different selector method if you want that viewController to behave differently when that notification is posted.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(somethingOtherThing:)
name:#"something"
object:nil];
-(void)somethingOtherThing:(NSNotification *) notification
{
// do something
}