1

我正在尝试使用 gcd 在后台加载图像。我的第一次尝试没有奏效:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{
  dispatch_async(dispatch_get_main_queue(), ^{
    // create UI Image, add to subview
  });
});

注释掉后台队列代码并只留下主队列调度块不起作用:

dispatch_async(dispatch_get_main_queue(), ^{
  // create UI Image, add to subview
});

在 gcd 块内做 ui 的东西有什么技巧吗?

为了回应 mattjgalloway 的评论,我只是想在后台线程中加载一个大图像。这是我最初尝试的完整代码:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{

    UIImage* img = [[UIImage alloc] initWithContentsOfFile: path];

    dispatch_async(dispatch_get_main_queue(), ^{

       imageView = [[[UIImageView alloc] initWithImage:  img] autorelease];
       imageView.contentMode = UIViewContentModeScaleAspectFill;
       CGRect photoFrame = self.frame;
       imageView.frame = photoFrame;
       [self addSubview:imageView];

  });

});

我对其进行了简化,以便在主队列中运行所有内容,但即便如此它也不起作用。我想如果我不能让整个事情在主队列中工作,那么后台队列的东西就不会工作。


================ 更新 ==============

我在一个全新的项目中尝试了上述技术(gcd 和所有),它确实按预期工作。只是不在我目前的项目中。所以我必须做一些缓慢而痛苦的消除工作来找出问题所在。我正在使用此背景加载在 uiscrollview 中显示图像。事实证明,有时会出现一些图像,但并非总是如此。我会深入了解这个......

================ 更新 ==============

看起来问题与 UIScrollView 有关,所有这些都在里面。我认为应该绘制/刷新的东西没有

4

3 回答 3

1

我运行了你的代码。它有一个例外。你的意思是self.view而不是self吗?

情况1:

路径在属性中声明。
imageView 在 ivar 中声明

- (IBAction)buttonImagePressed:(id)sender 
{
    self.path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"picture1.jpg"];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{
        UIImage* img = [[UIImage alloc] initWithContentsOfFile: self.path];  
        dispatch_async(dispatch_get_main_queue(), ^{
            imageView = [[[UIImageView alloc] initWithImage:  img] autorelease];
            imageView.contentMode = UIViewContentModeScaleAspectFill;
            CGRect photoFrame = self.view.frame;
            imageView.frame = photoFrame;
            [self.view addSubview:imageView];
        });
    });
}

案例二:

path 和 imageView 都是 ivars。- 不使用任何属性。

- (IBAction)buttonImagePressed:(id)sender 
{
// will crash if path is defined here
//    path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"picture1.jpg"];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{
        //if path is defined here then it will work
        path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"picture1.jpg"];
        UIImage* img = [[UIImage alloc] initWithContentsOfFile:path];
        dispatch_async(dispatch_get_main_queue(), ^{
            imageView = [[[UIImageView alloc] initWithImage:  img] autorelease];
            imageView.contentMode = UIViewContentModeScaleAspectFill;
            CGRect photoFrame = self.view.frame;
            imageView.frame = photoFrame;
            [self.view addSubview:imageView];
        });
    });
}

在案例 2 中,它崩溃了,控制台中的消息说要在 apple.com 上提交错误...

于 2012-05-22T02:10:22.843 回答
1

尝试在setNeedDisplay之后立即调用[self addSubview:imageView],顺便说一下,大多数 UIKit 都不是线程安全的,我不知道具体的 UIImage 方法(可能在 iOS4 及更高版本上还可以),但我不会那样做。如果您想更好地从后台加载图像,请使用线程安全的 ImageIO 或 Core Graphics 函数。
另一种方法是在后台线程上加载带有图像数据的 NSData 对象,然后[UIImage alloc]inithWithData: data]在主线程上调用。

于 2012-05-22T05:22:05.203 回答
0

将我的图像显示为背景图像,而不是将 UIImageView 添加为子视图。不知道为什么

@interface PhotoView(){
  UIImageView* imageView;
}

@end


@implementation PhotoView

-(id)initWithFrame:(CGRect)frame andPathToPhoto:(NSString*)path andSequenceView:(SequencerView*) sequencerView{
  if(self = [super initWithFrame:frame]){


    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{
      UIImage* img = [[UIImage alloc] initWithContentsOfFile: path];
      dispatch_async(dispatch_get_main_queue(), ^{
        self.backgroundColor = [UIColor colorWithPatternImage:img];
      });
      [img release];
    });

  }
  return self;
}

@end
于 2012-06-01T20:59:42.930 回答