开发者

NSNotification addObserver:someOtherClass

开发者 https://www.devze.com 2023-02-06 00:13 出处:网络
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

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.

  1. Delegation: ObjectA sets a property on ObjectB to point back to ObjectA, now B can send messages to A directly. Now your two objects are coupled together which can be both useful and problematic.
  2. 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消