Question

I'm new to GCD, and what seems to be a simple use of it doesn't work for me. I have the following code:

+ (void)synchronizationTimerFired:(NSTimer *)theTimer
{
    if ((synchronizationUpNeededFlag) || (synchronizationDownNeededFlag))
    {
        if ((!synchronizationUpInProgressDepthQuantity) && (!synchronizationDownInProgressDepthQuantity))
        {
            dispatch_queue_t synchronizationQueue = dispatch_queue_create("synchronizationQueue",NULL);
            dispatch_async(synchronizationQueue, ^(void) {

                NSLog(@"Top");
                ...code...
                ...code...
                ...code...
                NSLog(@"Bottom");

            });
        }
    }

    // Check if there is no timer, or if it is not currently valid,
    // and yet if synchronization is turned on,
    // then establish a repeating timer to attend to synchronization related matters.
    if ((!synchronizationTimer) || (!synchronizationTimer.isValid))
    {
        if (synchronizationOnFlag)
        {
            synchronizationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(synchronizationTimerFired:) userInfo:nil repeats:YES];
        }
    }
}

The log reads "Top" and nothing else. The code in the middle doesn't have an endless loop- it just never executes all the way through. I can put breakpoints in the code in the middle and there's a point where the program execution will break, and after which it won't. And there's a point right in the middle where sometimes the execution will stop at the breakpoint and other times it doesn't.

It seems to me as though the synchronizationQueue dispatch queue is being deallocated, but I can't call dispatch_retain because the compiler complains that dispatch_retain cannot be used in ARC. What am I missing?

In response to people asking about the code in-between, the program execution stops in this method call (represented by one of those lines of ...code...) at the line that says if (fetchArray.count), commented below.

+ (NSDate *)latestParseReceivedDownUpdatedAtDateForCoreDataEntityNameString:(NSString *)coreDataEntityNameString
{
    NSDate *functionReturnValue = nil;

    // Create fetchRequest
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:coreDataEntityNameString];

    // Set sort descriptor
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"parseReceivedDownUpdatedAtDate" ascending:NO]]];

    // We are only interested in one result
    [fetchRequest setFetchLimit:1];

    // Execute fetchRequest
    NSError *fetchError = nil;
    NSArray *fetchArray = [JBSAPPDELEGATE.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];

    if (fetchArray == nil)
    {
        NSLog(@"Unresolved error %@, %@", fetchError, [fetchError userInfo]);
        abort();
    }

    // If there are any records at all in our persistent store, we'll have exactly one.
    // But that doesn't mean it won't be nil, as if that record has never come down from
    // parse it will be a nil date on the managed object.
    if (fetchArray.count) // PROGRAM EXECUTION STOPS EITHER HERE, OR JUST BEFORE HERE
    {
        NSManagedObject *managedObject = [fetchArray objectAtIndex:0];
        functionReturnValue = [managedObject valueForKey:@"parseReceivedDownUpdatedAtDate"];
    }

    return functionReturnValue;
}

I will add that if I simply comment out the call to dispatch_async that everything executes fine. It just executes on the main thread, which I'd rather have it not do.

Was it helpful?

Solution

Is your managedObjectContext an NSManagedObjectContext? If so, did you create a managed object context on the specific thread that you are using for your dispatch queue? If you read the docs on NSManagedObjectContext, it says:

...a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method. You should not, therefore, initialize a context on one thread then pass it to a different thread. Instead, you should pass a reference to a persistent store coordinator and have the receiving thread/queue create a new context derived from that.

OTHER TIPS

I bet you created yourself a deadlock somewhere.

Use the debugger. Check what every thread is doing. You'll probably find some thread that you think should be continuing and isn't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top