1

UIScrollView内にUIImageを表示するだけの単純なCS193PiTunesUの例/宿題を変更しようとしました。私はObj-Cブロックを初めて使用します。

画像をダウンロードするコード行を*dispatch_async*ブロック内にラップしようとするとすぐに、ズームを解除して、

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
4

1 に答える 1

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);
}
于 2013-02-20T23:42:42.517 に答える