5

Basically: a method needs to return a NSDictionary that is fetched within a dispatch_async. This is what I have tried:

- (NSDictionary *)fetchNSDictionary {
    dispatch_queue_t Queue = dispatch_queue_create("Dictionary fetcher", NULL);
    dispatch_async(Queue, ^{
        NSDictionary *dict = ...
        dispatch_async(dispatch_get_main_queue(),^{
            return dict;
        )};
    )};
}

Result:

Incompatible block pointer types passing 'NSDictionary *(^)(void)' 
to parameter of type 'dispatch_block_t' (aka 'void (^)(void)')

Any ideas?

Undo
  • 25,519
  • 37
  • 106
  • 129
JasperJ
  • 1,192
  • 1
  • 12
  • 23
  • 1
    Strictly, the requirement "A method needs to return a NSDictionary that is fetched within a dispatch_async" cannot be fulfilled. When the method returns, by definition of what asynchronous means, the result is not yet evaluated. Thus, you cannot get the result returned, unless you force that method to become synchronous - which however is an "anti pattern", "code smell", bad practice, and other not that good things ;) – CouchDeveloper Nov 25 '13 at 12:11
  • My nose got blocked, so I didn't realize how bad this concept smelled until Undo's answer. – JasperJ Nov 25 '13 at 12:41

1 Answers1

5

When you say return dict;, you are actually trying to return dict to the caller of the dispatch block (the automated process that runs background asyncs) - which doesn't work.

Since you are using an asynchronous method, you can't return data received in a block back to the method you started the network operation in. By the time the code in that block is called, the system is long done with executing that method.

What you need to do instead is set up a delegate system - if this is a helper class, you could add a protocol including a method like didFinishLoadingStuff:(NSDictionary *)stuff.

You would then change

 - (NSData *) fetchNSDictionary{...}

To something like

- (void)getDictionaryWithDelegate:(NSObject<StuffGetterProtocol> *)delegate{...}

And instead of return dict;, you would say:

[delegate didFinishLoadingStuff:dict];

And of course implement the delegate method in whatever class you are calling this from:

- (void)didFinishLoadingStuff:(NSDictionary *)stuff
{
    //do something with stuff
}
Undo
  • 25,519
  • 37
  • 106
  • 129
  • 1
    Since he is using blocks already, I would suggest to put his callback into a block. Your method sure makes sense but if he needs it just once, I think it's too much clutter ;) – Nils Ziehn Nov 24 '13 at 22:15