I need to pass a message up to a controlling class (which creates an instance of the class which will be sending the message) So, I cannot directly reference the class name in my file, without either making it a Global (which is ridiculous to do if "NSNotification" advertises to be able to pass all kinds of messages, regardless of where / what class they are.
So without further ado...
(calling from Say ClassB)
ClassA creates instance of ClassB
Now in ClassB
, I need to pass messages regarding button presses back up to ClassA
(insdie ClassB)
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:ClassA
selector:@selector(doLoginAction)
name:@"SomeButton"
object:nil];
[super viewDidLoad];
}
This will NOT compile, even when I include, sorry, "#import "ClassA.h"
Now if I do something stupid like,
ClassA *classa = [[ClassA alloc]init];
and then use this Newly created instance of classa in addObserver:classa
it will compile, but as I thought, will do absolutely nothing... (I knew that, but surprisingly this kind of code is prevalent in Iphone programming books...) So I tried it anyway.
But if I put this function in ClassA
and use addObserver:ClassB
it wi开发者_Go百科ll get called, but will cause a stack dump unrecognized selector sent to instance
or use addObserver:self
.
I am tempted to delete Xcode and go back to vim and use a good old "C" callback...
So, if I get it right, you have a ClassA
which creates instances of ClassB
. Those instances, in turn, should send notifications directly to ClassA
without knowing anything about it.
If that is correct, then NSNotificationCenter is exactly what you need.
In ClassA
implementation add an initialialize
method like this:
@implementation ClassA
+ (void)initialize
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(YourSelector:)
name:@"YourNotificationName"
object:nil];
}
+ (void)YourSelector:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
// ...
}
// ...
@end
Then, instances of ClassB
should post their notifications using only its name:
@implementation ClassB
- (void)postNotification
{
NSDictionary *userInfo = ...; // may be nil
[[NSNotificationCenter defaultCenter]
postNotificationName:@"YourNotificationName"
// the same name is used in the `addObserver` call
// in the previous code snippet
object:nil
userInfo:userInfo];
}
// ...
@end
To sum it all up, you do not need to know anything about the receiver of notifications if you are using NSNotificationCenter. In fact, you may subscribe as many objects as you like to receive the same notification, and each of them will call its appropriate method (specified in addObserver
) upon receiving the notification object.
Please remember that in the case when you add a class instance as an observer, rather than the class object itself, you should call [[NSNotificationCenter defaultCenter] removeObserver:self]
in that instance's dealloc
method.
I see a couple of problems here.
First you need to stop trying to use classes and instances interchangeably. Until you have a reasonable mental model of what your classes and instances represent and what they are responsible for you're going to have all sorts of confusion around when to use which one and OOP in general.
NSNotificationCenter
allows you to register a specific instance of a class, a single object, as an observer of particular notifications. You need to be aware of, and have a reference to, the observing object in order to register it as an observer.
Secondly you need to consider what each of your classes, and therefor their instantiated objects are responsible for. What they should know, what they do not need to know, and how they can communicate.
Let's assume you create ObjectA
as an instance of ClassA
and it creates ObjectB
which is an instance of ClassB
. Now ObjectA
is aware of ObjectB
, after all A just created B so it is easy for A to have a reference to B. ObjectB
is not yet aware of ObjectA
; B was created but it need not know by which object or even what class that object was an instance of. If you want ObjectB
to be able to communicate with ObjectA
you have a couple of options.
- Delegation:
ObjectA
sets a property onObjectB
to point back toObjectA
, now B can send messages to A directly. Now your two objects are coupled together which can be both useful and problematic. - Notifications:
ObjectB
can post notifications,ObjectA
can observe notifications. B does not need to know that A is observing those notifications and A does not need to know that the notifications originated with B (though it could). These objects are very loosely coupled and you could change many things about your application without them ever being aware of it.
Importantly, if ObjectA
is to listen for notifications then it is A's responsibility to add itself as an observer. Since B is not aware of A there's no way B can make A an observer. A's creator could since that object would have a reference to A but A's children cannot unless they were given some reference to A.
Looks like Alex chimed in with an excellent answer so hopefully this will all be useful.
精彩评论