tranvutuan
tranvutuan

Reputation: 6109

I think I get a deadlock but not quite understand why

I am trying to place an image one after another using GCD like following

-(void)setUpImages {
    NSArray *images  =   @[[UIImage imageNamed:@"blogger-icon.png"],
                           [UIImage imageNamed:@"gplus-icon.png"],
                            [UIImage imageNamed:@"facebok-icon.png"]
                           ];
    [images enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
          dispatch_sync(dispatch_get_main_queue(), ^{
                UIImageView     *imageView  =   [[UIImageView alloc] initWithFrame:CGRectMake(80, idx * ((UIImage*)obj).size.height + idx*30 + 10, ((UIImage*)obj).size.width, ((UIImage*)obj).size.height)];
                NSLog(@"index is %@",NSStringFromCGRect(imageView.frame));

                [imageView setImage:(UIImage*)obj];
                [self.view.layer addSublayer:imageView.layer];
                sleep(1); 
            });
    }];

}

I am using dispatch_sync because I want it will wait until its block is done ( first image is placed on the screen) then second images will be and so the third one does. And all thing are happening on the main thread now.

However, it seems I am getting a deadlock in the middle and my logic is wrong at some points.

I need help to understand this situation. Please help.

Upvotes: 0

Views: 152

Answers (3)

Gabriele Petronella
Gabriele Petronella

Reputation: 108169

From the documentation of dispatch_sync:

Calling this function and targeting the current queue results in deadlock.


That said, I think you have a design problem and you can achieve the desired result without involving GCD.

Since it looks like you want to update the UI every k seconds, avoid using sleep(1) and invoke a method recursively with a delay using performSelector:withObject:afterDelay:.

Something like

- (void)updateImageViewWithImageAtIndex:(NSNumber *)i {
    UIImage * image = self.images[i.intValue];
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(80, idx * image.size.height + idx*30 + 10, image.size.width, image.size.height)];
    NSLog(@"index is %@",NSStringFromCGRect(imageView.frame));
    [imageView setImage:image];
    [self.view.layer addSublayer:imageView.layer];

    if (i < images.count - 1) {
        [self performSelector:@selector(updateImageViewWithImageAtIndex:) withObject:@(i.intValue++) afterDelay:1];
    }
}

- (void)setUpImages {
    // Assuming you have declared images as a property
    self.images = @[[UIImage imageNamed:@"blogger-icon.png"],
                        [UIImage imageNamed:@"gplus-icon.png"],
                        [UIImage imageNamed:@"facebok-icon.png"]
                       ];
    [self updateImageViewFromImages:images index:0];
}

Upvotes: 6

Duncan C
Duncan C

Reputation: 131491

I think Gabriele nailed the deadlock above. Don't call dispatch_sync and pass in the main queue.

Another possible problem: I suspect that manipulating a layer's views is not thread-safe. It shouldn't cause a deadlock, but it could cause undesirable consequences.

Upvotes: 0

Mick MacCallum
Mick MacCallum

Reputation: 130222

Now I may be completely wrong here, but it looks like all you're trying to do is change the image in an image view once a second, in which case your approach is incorrect. UIImageView has methods for this built in. For example:

NSArray *images  =   @[[UIImage imageNamed:@"blogger-icon.png"],
                       [UIImage imageNamed:@"gplus-icon.png"],
                       [UIImage imageNamed:@"facebok-icon.png"]
                       ];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(80, idx * ((UIImage*)obj).size.height + idx*30 + 10, ((UIImage*)obj).size.width, ((UIImage*)obj).size.height)];
[imageView setAnimationDuration:3];
[imageView setAnimationImages:images];
[imageView startAnimating];

Upvotes: 2

Related Questions