1

这个问题的最终解决方案在问题下方给出

我的目标是创建一个图像选择器,它最初在滚动视图内创建每个图像视图,然后将该图像视图的引用传递给一个方法,该方法将使用适当的图像异步更新 imageview.image。

这工作得很好。

我遇到的问题是滚动视图仅在方法结束时批量显示图像视图,而我希望它们在创建时一个接一个地打印(图像是否可用)。

如果我触摸滚动视图来滚动,它会按照我想要的方式工作,但是如果我根本不触摸,屏幕会保持白色,直到所有图像(不仅仅是图像视图)都完成加载。

我已经尝试将 setNeedsDisplay 放置在任何地方,每个视图,包括 self.view、scrollview 和每个单独的 imageview。这是怎么回事?

- (void)viewDidLoad {
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
     dispatch_async(queue, ^{
          [self setGridView];
     });
}

- (void)setGridView {
    // begin loading images
    NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? @"2" : @"";

    CGRect scrollframe = CGRectMake(0, 0, 300, 275);
    UIScrollView * newscrollview;
    newscrollview = [[UIScrollView alloc] initWithFrame:scrollframe];
    newscrollview.scrollEnabled = YES;
    newscrollview.delegate = self;
    [newscrollview setContentSize:CGSizeMake(300, (((ceilf([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]] count]/4)) * (58+15)) + 15 + 58 + 15))];
    [picsMVContentCell.contentView addSubview:newscrollview];

    float currentx = 11;
    float currenty = 17;
    NSInteger index = 0;

    for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]]) {

        // create button
        UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(currentx, currenty, 58, 58);
        button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
        button.imageView.contentMode = UIViewContentModeScaleAspectFit;
        button.imageView.layer.cornerRadius = 6;
        button.imageView.layer.masksToBounds = YES;
        button.imageView.accessibilityLabel = [d objectForKey:@"id"];
        button.imageView.accessibilityValue = [d objectForKey:@"full"];
        button.imageView.tag = index++;
        [button addTarget:self action:@selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];

        UIImage * image = [MVImage imageWithImage:[UIImage imageNamed:@""] covertToWidth:58.0f covertToHeight:58.0f];
        [button setImage:image forState:UIControlStateNormal];

        [newscrollview addSubview:button];
        [newscrollview bringSubviewToFront:button];
        [newscrollview setNeedsDisplay];

        // calculate next image view position
        currentx += (button.imageView.frame.size.width+15);
        if (currentx >= 289) {
            currentx = 11;
            currenty += (button.imageView.frame.size.height+15);
        }

        // set image
        NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
        if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
            MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
            [button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
        } else {
            [MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
        }
    }
}

编辑于 2012 年 2 月 7 日下午 3:26

这些更改修复了与问题中给出的代码相关的所有问题

感谢@Eugene 为我指明了正确的方向

/* ---------- ---------- ---------- ---------- ---------- */

- (void)viewDidLoad {
     [super viewDidLoad];

     [[MVProject sharedInstance] syncLoadSF:0];

    self.newscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 300, 275)];
    self.newscrollview.scrollEnabled = YES;
    self.newscrollview.delegate = self;
    [self.newscrollview setContentSize:CGSizeMake(300, (((ceilf(([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]] count]-1)/4)) * (58+15)) + 15 + 58 + 15))];
    [picsMVContentCell.contentView addSubview:self.newscrollview];

    [self setGridView];
}

/* ---------- ---------- ---------- ---------- ---------- */

- (void)setGridView {
    NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? @"2" : @"";
    [self.newscrollview setNeedsDisplay];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        NSInteger index = 0;
        for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]]) {
            // create button
            UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];               
            button.frame = CGRectMake((11 + ((index%4)*(58+15))), (17 + ((floorf(index/4))*(58+15))), 58, 58);
            button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
            button.imageView.contentMode = UIViewContentModeScaleAspectFit;
            button.imageView.layer.cornerRadius = 3;
            button.imageView.layer.masksToBounds = YES;
            button.imageView.accessibilityLabel = [d objectForKey:@"id"];
            button.imageView.accessibilityValue = [d objectForKey:@"full"];
            button.imageView.tag = index++;
            [button addTarget:self action:@selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];

            dispatch_sync(dispatch_get_main_queue(), ^ {
                [button setImage:[MVImage imageWithImage:[UIImage imageNamed:@""] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
                [self.newscrollview addSubview:button];
                [self.newscrollview bringSubviewToFront:button];
                [self.newscrollview setNeedsDisplay];

                // set image
                NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
                if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
                    MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
                    [button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
                } else {
                    [MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
                }
            });
        }
    });
    [self.newscrollview setNeedsDisplay];
}
4

2 回答 2

2

您不能在后台线程上进行绘图。每次添加子视图时,都应该在主线程中执行此操作。所以你的救赎是在同步块中使用你的绘图代码,它在主队列上运行

  dispatch_sync(dispatch_get_main_queue(), ^ {
    [newscrollview addSubview:button];
    [newscrollview bringSubviewToFront:button];
    [newscrollview setNeedsDisplay];

    // calculate next image view position
    currentx += (button.imageView.frame.size.width+15);
    if (currentx >= 289) {
      currentx = 11;
      currenty += (button.imageView.frame.size.height+15);
    }

    // set image
    NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
    if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
      MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
      [button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
    } else {
      [MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
    }
  });
于 2012-02-07T18:24:53.097 回答
0

您遇到的问题是设置图像。您尝试做的是将所有图像容器添加到滚动视图。然后当图像准备好时将它们加载到它们的容器中。有两种方法可以做到这一点。

首先将所有容器添加到滚动视图。(您可能需要一些加载指示器或默认图像来显示其加载)

1)创建一个后台线程来准备图像。当图像准备好后,将其添加到其容器中。(我发现这种方式更辛苦,有点痛苦)

2)创建自定义容器,让自定义容器在镜像准备好后添加自己的镜像。

例如,我正在从服务器加载图像。所以我创建了 AsyncImage 类,它是 UIImageView 的自定义类。我创建了一个函数,我将图像 url 发送到它并处理其余部分。它创建一个 NSURLConnection 并在加载数据时调用self.image = [UIImage imageWithData:data];

于 2012-02-07T18:41:59.343 回答