【问题标题】:Objective C: Download Thread not affecting UI, even possible?目标C:下载线程不影响UI,甚至可能吗?
【发布时间】:2012-11-18 12:01:08
【问题描述】:

我正在学习 ItunesU 上的斯坦福课程,他们说下载内容的线程不应该对 UI 做任何事情,这应该只发生在主线程上。

好吧,在我的示例中,我正在从 Flicker 下载一张图片,并且我想在 UIScrollView 中设置这张图片(通过 segue)。因此,当我在“侧面”线程中下载这张图片时,我将UIScrollview 的图像属性设置为图像等。但这显然不起作用,因为我还不知道图像大小而且我也尚未设置正确的对该图像对象的引用?

那你是怎么处理的呢?我希望我很清楚..这是我的例子:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(NSIndexPath *)sender{
NSDictionary *selectedPhoto = [self.photos objectAtIndex:sender.row];

    [self.defaults addPhotoToRecentlyViewed:selectedPhoto];
    [self.defaults saveDefaults];

    PhotoViewer *photoViewer = segue.destinationViewController;

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    photoViewer.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:spinner];
    [spinner startAnimating];

    dispatch_queue_t photoDownload = dispatch_queue_create("photoviewever", nil);

    dispatch_async(photoDownload, ^{        
        NSData *data = [NSData dataWithContentsOfURL:[FlickrFetcher urlForPhoto:selectedPhoto format:FlickrPhotoFormatLarge]];
        UIImage *image = [UIImage imageWithData:data];
        photoViewer.image = image;

        dispatch_async(dispatch_get_main_queue(), ^{

            photoViewer.title = [selectedPhoto objectForKey:FLICKR_PHOTO_TITLE];
            photoViewer.navigationItem.rightBarButtonItem = nil;
        });
    });
}

还有我的 PhotoViewer:

#import "PhotoViewer.h"

@interface PhotoViewer ()

@property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
@property (nonatomic, strong) IBOutlet UIImageView *imageView;

@end

@implementation PhotoViewer

@synthesize scrollView = _scrollView;
@synthesize imageView = _imageView;
@synthesize image = _image;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.scrollView.delegate = self;
    [self setupImage];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return self.imageView;
}

- (void)setupImage{
    self.imageView.image = self.image;
    self.imageView.frame = CGRectMake(0, 0, self.image.size.width, self.image.size.height);
    self.scrollView.contentSize = self.image.size;
    [self.imageView setNeedsDisplay];
}

@end

【问题讨论】:

  • 那么你的问题是什么?你能得到图像并将其显示在你的 UIScrollView 上吗?
  • 其实不是。当我在 photoViewer 中更改图像的设置器并且只在那里进行设置时,我可以显示它。但是滚动并没有真正起作用,当我从另一个选项卡返回图像时,它完全滚动出去并且根本不起作用。我只是想知道这个线程应该如何工作。因为在我的下载线程中,我将 photoViewer.image 设置为下载的图像,但仅在下载图像之后。但是 PhotoViewer 中的引用是在下载图像之前设置的……所以我有点困惑……应该怎么做?
  • 我觉得在 prepareForSeague 方法中下载图像不是一个好主意。当视图完全加载时,为什么不下载它。当然你也可以覆盖新视图控制器中的setter方法,看看它是否真的加载了,然后设置图像。

标签: objective-c grand-central-dispatch cs193p


【解决方案1】:

你应该移动这条线:

        photoViewer.image = image;

进入您分派回主线程的“完成”块。 PhotoViewer 似乎是一个视图控制器,因此它受制于与其他 UI 相同的“仅主线程”规则。此外,您似乎需要从该主线程“完成”块再次调用-setupImage。 (否则图像将永远不会被推送到图像视图中,如您所述。)

同样在-setupImage 中,您要检查self.image 在寻址之前是否返回一个非零值。根据您使用的编译器,调用返回结构的 Objective C 方法的行为是“未定义的”(即 self.image.size 返回 CGSize 结构)。 (虽然在最近的编译器中,它returns a zero filled struct.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-28
    • 2011-12-27
    • 2021-11-20
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多