Blocks / dispatch_async:我的简单代码出了什么问题?

时间:2013-02-20 22:40:33

标签: objective-c cocoa-touch objective-c-blocks grand-central-dispatch

我尝试修改简单 CS193P iTunes U示例/家庭作业,只在UIScrollView 中显示 UIImage。我是Obj-C区块的新手。

一旦我尝试将下载Image的代码行包装在* dispatch_async * Block中,我就会打破缩放并获得

Uncaught exception: CALayer position contains NaN: [nan nan]

(显示图像和“滚动”工作)

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [self.activityIndicatorView startAnimating];

    [self resetImage];
}

- (void)resetImage
{
    if (self.detailItem && self.scrollView) {
        //reset 
        self.scrollView.contentSize = CGSizeZero;
        self.imageView.image = nil;

        NSURL *imageURL = [FlickrFetcher urlForPhoto:self.detailItem format:FlickrPhotoFormatLarge];

        __block NSData *imageData;

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            imageData = [[NSData alloc] initWithContentsOfURL:imageURL];

            dispatch_async(dispatch_get_main_queue(), ^{    //because of UI Stuff

                UIImage *image = [[UIImage alloc] initWithData:imageData];
                if (image) {                        
                    [self.activityIndicatorView stopAnimating];
                    [self.activityIndicatorView removeFromSuperview];

                    self.scrollView.zoomScale = 1.0;
                    self.scrollView.contentSize = image.size;
                    self.imageView.image = image;

                    CGRect frame = { CGPointZero , image.size };
                    self.imageView.frame = frame;

                    [self addToRecentPhotosList:self.detailItem];

                    NSLog(@"\n self.imageView.frame:%@ \n self.imageView.bounds: %@ \n self.scrollView.contentSize: %@ \n self.scrollView.frame: %@ \n self.scrollView.bounds: %@ ", NSStringFromCGRect(self.imageView.frame), NSStringFromCGRect(self.imageView.bounds), NSStringFromCGSize(self.scrollView.contentSize), NSStringFromCGRect(self.scrollView.frame), NSStringFromCGRect(self.scrollView.bounds));
                }

            });
        });

    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.scrollView addSubview:self.imageView];
    [self.scrollView addSubview:self.activityIndicatorView];
    self.scrollView.minimumZoomScale = 0.2;
    self.scrollView.maximumZoomScale = 5.0;
    self.scrollView.delegate = self;
}
- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    if  (self.imageView.image)  [self.scrollView zoomToRect:self.imageView.bounds animated:YES];
    else                        self.activityIndicatorView.center = self.view.center;

}


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

记录的帧/边界:

without dispatch_async blocks:
self.imageView.frame: {{0, 0}, {1024, 768}}
self.imageView.bounds: {{0, 0}, {1024, 768}}

with dispatch_async blocks:
self.imageView.frame: {{-7.62939e-06, -1.52588e-05}, {1024, 768}}  
self.imageView.bounds: {{0, 0}, {204.8, 153.6}}  
self.scrollView.contentSize: {1024, 768}
self.scrollView.frame: {{0, 0}, {320, 367}}
self.scrollView.bounds: {{0, 0}, {320, 367}}

堆栈追踪:

0   CoreFoundation                      0x01ca002e __exceptionPreprocess + 206
1   libobjc.A.dylib                     0x010dde7e objc_exception_throw + 44
2   CoreFoundation                      0x01c9fdeb +[NSException raise:format:] + 139
3   QuartzCore                          0x02293e0b _ZN2CA5Layer12set_positionERKNS_4Vec2IdEEb + 151
4   QuartzCore                          0x0229eba1 -[CALayer(CALayerPrivate) setDoublePosition:] + 81
5   UIKit                               0x000874a2 -[UIScrollView setZoomScale:withAnchorPoint:validatingScrollOffset:allowRubberbanding:animated:duration:notifyDelegate:force:] + 1476
6   UIKit                               0x00083004 -[UIScrollView _updatePinchGestureForState:] + 3499
7   UIKit                               0x00083960 -[UIScrollView handlePinch:] + 59
8   UIKit                               0x002ec85a _UIGestureRecognizerSendActions + 139
9   UIKit                               0x002eb99b -[UIGestureRecognizer _updateGestureWithEvent:] + 333
10  UIKit                               0x002ed0df -[UIGestureRecognizer _delayedUpdateGesture] + 46
11  UIKit                               0x002efd2d ___UIGestureRecognizerUpdate_block_invoke_0543 + 57
12  UIKit                               0x002efcac _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 331
13  UIKit                               0x002e7a28 _UIGestureRecognizerUpdate + 1348
14  UIKit                               0x00054972 -[UIWindow _sendGesturesForEvent:] + 1283
15  UIKit                               0x00054e53 -[UIWindow sendEvent:] + 98
16  UIKit                               0x00032d4a -[UIApplication sendEvent:] + 436
17  UIKit                               0x00024698 _UIApplicationHandleEvent + 9874
18  GraphicsServices                    0x01bfbdf9 _PurpleEventCallback + 339
19  GraphicsServices                    0x01bfbad0 PurpleEventCallback + 46
20  CoreFoundation                      0x01c15bf5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
21  CoreFoundation                      0x01c15962 __CFRunLoopDoSource1 + 146
22  CoreFoundation                      0x01c46bb6 __CFRunLoopRun + 2118
23  CoreFoundation                      0x01c45f44 CFRunLoopRunSpecific + 276
24  CoreFoundation                      0x01c45e1b CFRunLoopRunInMode + 123
25  GraphicsServices                    0x01bfa7e3 GSEventRunModal + 88
26  GraphicsServices                    0x01bfa668 GSEventRun + 104
27  UIKit                               0x00021ffc UIApplicationMain + 1211
28  CS193P.4.SPoT                       0x00002b84 main + 164
29  CS193P.4.SPoT                       0x00002a95 start + 53

1 个答案:

答案 0 :(得分:2)

或许,如果你想在另一个线程上创建的线程上使用一个对象,那么首先将线程彼此同步是一个好主意。在准备使用之前开始使用imageData并不是一个屡获殊荣的想法。

// ...

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    dispatch_semaphore_t _semaphore = dispatch_semaphore_create(0);
    imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
    dispatch_semaphore_signal(_semaphore);

    dispatch_async(dispatch_get_main_queue(), ^{    //because of UI Stuff

        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
        dispatch_release(_semaphore);
        UIImage *image = [[UIImage alloc] initWithData:imageData];

        // etc...

    };
};

// ...

<强>更新

尝试此解决方案,它的工作方式与GCD版本应该有效。

<强> SPoTDetailViewController.h

@interface SPoTImageViewController : UIViewController <UISplitViewControllerDelegate, UIScrollViewDelegate> {
    dispatch_semaphore_t _semaphore;
    __block NSData *imageData;
}

// ...

@end

<强> SPoTDetailViewController.m

- (void)resetImage
{
    // Update the user interface for the detail item.
    [self.activityIndicatorView startAnimating];

    if (self.detailItem && self.scrollView) {
        self.scrollView.contentSize = CGSizeZero;
        self.imageView.image = nil;

        [self performSelectorInBackground:@selector(downloadImageDataOnBackgroundThread) withObject:nil];

        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
        // dispatch_release(_semaphore);
        UIImage *image = [[UIImage alloc] initWithData:imageData];
        if (image) {

            [_activityIndicatorView stopAnimating];

            _scrollView.zoomScale = 1.0;
            _scrollView.contentSize = image.size;
            _imageView.image = image;

            CGRect frame = { CGPointZero , image.size };
            NSLog(@"\n new CGRect frame:%@ \n ", NSStringFromCGRect(frame));

            _imageView.frame = frame;
            NSLog(@"\n self.imageView.frame:%@ \n self.imageView.bounds: %@", NSStringFromCGRect(self.imageView.frame), NSStringFromCGRect(self.imageView.bounds));
        }
    }
}

- (void)downloadImageDataOnBackgroundThread {
    _semaphore = dispatch_semaphore_create(0);
    NSURL *imageURL = [FlickrFetcher urlForPhoto:self.detailItem format:FlickrPhotoFormatLarge];
    imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
    dispatch_semaphore_signal(_semaphore);
}