Answer To Challenge: using a block with NSNotificationCenter


#1

HI All,

Here is the solution I came up with…it appears to work:

main.m

[code]#import <Foundation/Foundation.h>
#import “BNRLogger.h”

typedef void (^zoneChanged)(NSNotification *);

int main(int argc, const char * argv[])
{

@autoreleasepool {
    
    BNRLogger *logger = [[BNRLogger alloc] init];
    
    [[NSNotificationCenter defaultCenter]
     addObserverForName:NSSystemTimeZoneDidChangeNotification
     object:nil
     queue:nil
     usingBlock:^(NSNotification *note)
     {
         NSLog(@"The system time zone has changed via a block!");
     }];
    
    /*[[NSNotificationCenter defaultCenter]
     addObserverFor:logger
     selector:@selector(zoneChange:)
     name:NSSystemTimeZoneDidChangeNotification
     object:nil];
     */
    
    NSURL *url = [NSURL URLWithString:@"http://www.guttenberg.org/cache/epub/205/pg205.txt"];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    __unused NSURLConnection *retchConn = [[NSURLConnection alloc] initWithRequest:request
                                                                          delegate:logger
                                                                  startImmediately:YES];
    
    __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                      target:logger
                                                    selector:@selector(updateLastTime:)
                                                    userInfo:nil
                                                     repeats:YES];
    [[NSRunLoop currentRunLoop] run];
   
}

return 0;

}
[/code]


#2

Hello,

After reviewing your solution I found where I had my problem, which is I used logger instead of nil for ‘object’. Would be nice if anyone can pitch in and explain using nil for object in the method addObserverForName: object: queue: usingBlock:

[code]#import <Foundation/Foundation.h>
#import "BNRLogger.h"
int main(int argc, const char * argv[])
{

@autoreleasepool {
    BNRLogger *logger = [[BNRLogger alloc] init];
    
    // Using method
    /* [NSNotificationCenter defaultCenter] addObserver:logger
                                             selector:@selector(zoneChange:)
                                                 name:NSSystemTimeZoneDidChangeNotification
                                               object:nil]; */
    
    // Using block
    [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemTimeZoneDidChangeNotification
                                                      object:nil
                                                       queue:nil
                                                  usingBlock:^void(NSNotification *note){NSLog(@"The system time zone has changed!");}];
    
    NSURL *url = [NSURL URLWithString:@"http://www.gutenberg.org/cache/epub/205.txt"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    __unused NSURLConnection *fetchConn = [[NSURLConnection alloc] initWithRequest:request
                                                                          delegate:logger
                                                                  startImmediately:YES];
    
    __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                      target:logger
                                                    selector:@selector(updateLastTime:)
                                                    userInfo:nil
                                                     repeats:YES];
    [[NSRunLoop currentRunLoop] run];
    
}
return 0;

}[/code]


#3

Sarkha, I did exactly the same as you did. I passed logger for the object.
After giving the apple documentation on the particular method another glance I noticed this:

[quote] obj
The object whose notifications you want to add the block to the operation queue.
If you pass nil, the notification center doesn’t use a notification’s sender to decide whether to add the block to the operation queue.
[/quote]

That’s a straight copy paste from the Parameters section in the Documentation. I think it’s pretty self-explanatory, even though I missed it the first time I read through it as well.

To clarify: We used the instance *logger of BNRLogger to use the method zoneChange, but since we’re not using that method anymore, but simply want te method of NSNotificationCenter to use the block we made to be used there is no use of the entire object of BNRLogger. At least, not for this part in the code. Further on with the downloading of the file it’s still used, of course.

Thinking about it, I think it’s possible to somehwere put the block in the class BNRLogger to still use it like that, but that’s a bit too confusing for me to really figure out haha


#4

Yep, I had the same problem as others I had “object:logger” as soon as I changed to “object:nil” it worked fine. I was suspicious of “logger”, since the “zoneChange” method in “logger” didn’t seem to be in the game. Thanks for the pointer.


#5

I just wanted to note that this is a much better use-case for an anonymous function than the first challenge in this chapter.


#6

Can someone elaborate on the argument for the object: portion of

  • (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block ?

An example of using this method and not using nil for the argument for object: would be great!

Also I just came up with this questioned, is there a more appropriate way to refer to the different portions of a method and its arguments than I did above?
i.e.- saying “the argument for the object: portion of” seems poor/improper jargon