Ios 通过多个UIActivityIndicatorView正确使用Grand Central Dispatch
我正在创建一个由UIButtons组成的缩略图查看器,并希望在每个按钮中都有一个微调器,直到图像从云中填充。我以前用单纺纱机做过,但从来没有像这样大规模。微调器没有出现(可能是非主线程UI问题?)…我至少朝着正确的方向前进了吗?提前谢谢Ios 通过多个UIActivityIndicatorView正确使用Grand Central Dispatch,ios,uiactivityindicatorview,grand-central-dispatch,Ios,Uiactivityindicatorview,Grand Central Dispatch,我正在创建一个由UIButtons组成的缩略图查看器,并希望在每个按钮中都有一个微调器,直到图像从云中填充。我以前用单纺纱机做过,但从来没有像这样大规模。微调器没有出现(可能是非主线程UI问题?)…我至少朝着正确的方向前进了吗?提前谢谢 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_queue_t queue2 = dispatch_get_g
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_apply(numberOfThumbs, queue, ^(size_t i){
Post *post = [arrayOfPosts objectAtIndex:i];
UIActivityIndicatorView *newSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIButton *currentThumb = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
[currentThumb setFrame:CGRectMake((105.5 * (i%3))+3.5, ((i/3)*105.5) + 3.5, 102, 102)];
[newSpinner setFrame:CGRectMake(54 - spinner.frame.size.width/2, 54 - spinner.frame.size.height/2, spinner.frame.size.width, spinner.frame.size.height)];
[currentThumb addSubview:newSpinner];
[newSpinner startAnimating];
[thumbnails addObject:currentThumb];
dispatch_async(queue2, ^(void){
[currentThumb setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:post.thumbUrl]]] forState:UIControlStateNormal];
[newSpinner stopAnimating];
[newSpinner removeFromSuperview];
[newSpinner release];
});
[currentThumb release];
});
dispatch_release(queue);
dispatch_release(queue2);
多亏了丹尼尔和布拉德的建议,下面的舞蹈似乎奏效了:
- (id)initWithArrayOfPosts:(NSArray*)posts
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Custom initialization
arrayOfPosts = [posts retain];
numberOfThumbs = [arrayOfPosts count];
oldDequeueFactor = 0;
oldYOffset = 0.0;
thumbnails = [[NSMutableArray alloc] initWithCapacity:15];
mainScrollView = [[UIScrollView alloc] init];
[mainScrollView setFrame:self.view.frame];
[mainScrollView setContentSize:CGSizeMake(self.view.frame.size.width, 109 * (ceilf((float)numberOfThumbs/3.0)))];
[mainScrollView setDelegate:self];
[mainScrollView setBackgroundColor:[UIColor whiteColor]];
[self setView:mainScrollView];
for (int i=0; i<numberOfThumbs; i++) {
UIActivityIndicatorView *newSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIButton *currentThumb = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
[currentThumb setFrame:CGRectMake((105.5 * (i%3))+3.5, ((i/3)*105.5) + 3.5, 102, 102)];
[newSpinner setFrame:CGRectMake(54 - newSpinner.frame.size.width/2, 54 - newSpinner.frame.size.height/2, newSpinner.frame.size.width, newSpinner.frame.size.height)];
[currentThumb addSubview:newSpinner];
[newSpinner startAnimating];
[thumbnails addObject:currentThumb];
[currentThumb release];
[mainScrollView addSubview:[thumbnails objectAtIndex:i]];
[self getImageDataAsynchronouslyForThumbnail:[thumbnails objectAtIndex:i] forIndex:i andRemoveSpinner:newSpinner];
}
}
return self;
}
- (void)getImageDataAsynchronouslyForThumbnail:(UIButton*)thumb forIndex:(int)index andRemoveSpinner:(UIActivityIndicatorView *)spinner
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(queue, ^(void){
Post *post = [arrayOfPosts objectAtIndex:index];
UIImage *thisImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:post.thumbUrl]]];
NSArray *args = [NSArray arrayWithObjects:thisImage, thumb, spinner, nil];
if ([args count] == 3) { //use this array to verify I have all info I need
dispatch_sync(dispatch_get_main_queue(), ^(void) {
[self setImage:[args objectAtIndex:0] ForThumbnail:[args objectAtIndex:1] andStopAnimatingSpinner:[args objectAtIndex:2]];
});
} else {
[self getImageDataAsynchronouslyForThumbnail:thumb forIndex:index andRemoveSpinner:spinner];
return;
}
});
dispatch_release(queue);
}
- (void)setImage:(UIImage*)image ForThumbnail:(UIButton *)thumb andStopAnimatingSpinner:(UIActivityIndicatorView *)spinner
{
[thumb setImage:image forState:UIControlStateNormal];
[spinner stopAnimating];
[spinner removeFromSuperview];
[spinner release];
}
-(id)initWithArrayOfPosts:(NSArray*)posts
{
self=[super initWithNibName:nil bundle:nil];
如果(自我){
//自定义初始化
arrayOfPosts=[保留职位];
numberOfThumbs=[arrayOfPosts计数];
oldDequeueFactor=0;
oldYOffset=0.0;
缩略图=[[NSMutableArray alloc]initWithCapacity:15];
mainScrollView=[[UIScrollView alloc]init];
[mainScrollView设置框架:self.view.frame];
[mainScrollView setContentSize:CGSizeMake(self.view.frame.size.width,109*(celf((float)numberOfThumbs/3.0));
[mainScrollView setDelegate:self];
[mainScrollView setBackgroundColor:[UIColor whiteColor]];
[自设置视图:主滚动视图];
对于(int i=0;i是的,我认为您的问题是您正在从后台线程执行代码,UIKit不是线程安全的,因此您可能应该只在后台获取图像数据,然后使用performSelectorOnMainTHread来设置图像并停止动画,例如
-(void)setDataStopAnimating:(NSArray*)args
{
//get your arguments from the array and then run
[thumb setImage:[UIImage imageWithData:imageData] forState:UIControlStateNormal];
[newSpinner stopAnimating];
[newSpinner removeFromSuperview];
[newSpinner release];
}
//then in your queue code
dispatch_async(queue2, ^(void){
NSArray *args; //fill the array with the arguments
[self performSelectorOnMainThread:@selector(setDataAndStopAnimating:) withObject:args]
});
如果有帮助的话,该代码似乎适用于设备上的一些缩略图,而不是模拟器上的缩略图。在您修订的代码中,我相信您可以将-performSelectorInBackground:
替换为dispatch\u async(dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u DEFAULT,0),^{})
将所有内容保留在GCD内,避免为参数创建临时NSArray。哦,无论如何,这都应该执行SelectorInMainThread:withObject。让我修改一下,并尝试一些仅使用GCD的选项。谢谢。更新了Brad的建议,仅使用GCD进行线程。哦,好的。我会尝试一下。我从来没有混合过formSelector和GCD,谢谢。@diatrevolo我也没有试过,所以它可能不起作用,如果不起作用,那么您可以执行selectorOnBackground来获取数据,一定要让我们知道它是否起作用…UIImage*image=[UIImage imageWithData:imageData]是线程安全的,我认为。-它还缓存它,这可能不是期望的行为。除了-performselectornmainthread:
,您可以使用GCD方式dispatch\u sync(dispatch\u get\u main\u queue(),^{})
(或者dispatch\u async,如果您不想阻止,直到主线程操作完成)。这避免了传入参数数组的需要。