1

When I call the following function:

+ (void) myMethod:(NSString *) myConstString array: (NSArray *) myArray
{
    dispatch_block_t block = 
    ^{
        for (int i = 0; i < myArray.count; i++)
        {
            if ([@"myString1"  isEqual: myConstString])
                // Do some easy job here

            else if ([@"myString2"  isEqual: myConstString])
                // Do some other easy job here

            [NSThread sleepForTimeInterval: 0.5];
        }

        [[NSNotificationCenter defaultCenter] postNotificationName:@"test" object:nil userInfo:nil];
    };

    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.example.test", NULL);
    dispatch_async(backgroundQueue, block);
}

[[NSNotificationCenter...] is executed two times. I know that because method in other class which is responsible for "catch" this notification is called two times. First call is instant (and this is strange to me). Second call is after about 2 seconds (this call I like :-) ) I know how to "repair" this:

+ (void) myMethod:(NSString *) myConstString array: (NSArray *) myArray {
    dispatch_block_t block = 
    ^{
        Boolean isForLoopExecuted = false;
        for (int i = 0; i < myArray.count; i++)
        {
            if ([@"myString1"  isEqual: myConstString])
                // Do some easy job here

            else if ([@"myString2"  isEqual: myConstString])
                // Do some other easy job here

            [NSThread sleepForTimeInterval: 0.5];
            isForLoopExecuted = true;
        }
        if (isForLoopExecuted)
            [[NSNotificationCenter defaultCenter] postNotificationName:@"test" object:nil userInfo:nil];
    };

    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.example.test", NULL);
    dispatch_async(backgroundQueue, block); }

After addind isForLoopExecuted everything works propertly. There is only one call after 2 seconds. This suggests that for loop is not executed when first call is made. I am really curious why this is happening. Thanks for your time!

Trzy Gracje
  • 2,969
  • 4
  • 20
  • 24
  • Have you cross verified that you are not firing the same notification from anywhere else within the code?? Adding a variable to check execution doesn't make sense. If block is getting executed than your notification will get called anyway. – Gandalf Dec 05 '14 at 09:50

1 Answers1

1

First off, creating new background queue every time that function runs is probably not what you want. There are limits how many queues you can have, and this is right way to reach that limit quickly and crash. Use something like this:

dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), block);

Secondly, there is nothing wrong with first listing (except that background queue) and it works correctly. Notification will be sent just once.

What I would suggest is to put log when you are sending notification to see exactly how many times you are executing that function. Probably more than once. Also, time that will be spent in queue depends on parameters you are sending there. If myArray is empty, you get notification almost immediately.

Juraj Antas
  • 3,059
  • 27
  • 37
  • Thank you for your answer. Can you explain me how dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), block); works? – Trzy Gracje Dec 05 '14 at 13:26
  • dispatch_get_global_queue will return system background queue, that you can use. All you need to specify there is priority, in this example I used QOS_CLASS_UTILITY. I suggest to check documentation about concurrent programing here: https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html – Juraj Antas Dec 05 '14 at 13:34