Reputation: 6109
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
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
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
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