【问题标题】:Drawing to context on background thread在后台线程上绘制上下文
【发布时间】:2011-06-27 12:07:29
【问题描述】:

我有一个 UIView 必须显示一些信息。由于这个视图非常复杂并且绘图需要大量时间,因此我将其移至后台线程以避免阻塞主线程。绘制完成后,我派回主线程设置 ImageView。

以下代码为我绘制,但我偶尔会收到一些崩溃。通常 xcode 指向[view release]; 并说Thread 6: Program received signal: EXC_BAD_ACCESS

NSManagedObjectID *objectID = [self.managedObject objectID];
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
        dispatch_async(queue,^{
            NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init];
            [backgroundContext setPersistentStoreCoordinator:[[self.managedObject managedObjectContext] persistentStoreCoordinator]];
            NSManagedObject *mo = [backgroundContext objectWithID:objectID];
            CGImageRef resultImage;
            CGContextRef context;
            void *bitmapData;

    CGRect frame = self.frame;
    frame.origin = CGPointZero;

    CGColorSpaceRef colorSpace;
    CGSize canvasSize;
    int bitmapByteCount;
    int bitmapBytesPerRow;

    canvasSize = frame.size;
    CGFloat scale = [UIScreen instancesRespondToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0f;
    canvasSize.width *= scale;
    canvasSize.height *= scale;

    bitmapBytesPerRow = (canvasSize.width * 4);
    bitmapByteCount = (bitmapBytesPerRow * canvasSize.height);

    //Create the color space
    colorSpace = CGColorSpaceCreateDeviceRGB();

    bitmapData = malloc( bitmapByteCount );

    //Check the the buffer is alloc'd
    if( bitmapData == NULL ){
        DLog(@"Buffer could not be alloc'd");
    }

    //Create the context
    context = CGBitmapContextCreate(bitmapData, canvasSize.width, canvasSize.height, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
    CGContextClearRect(context, CGRectMake(0, 0, canvasSize.width, canvasSize.height));

    // Setup transformation
    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
    CGContextTranslateCTM(context, 0.0f, canvasSize.height); 
    CGContextScaleCTM(context, scale, -scale);

    UIView *view = [[UIView alloc] initWithFrame:frame];
    [view setBackgroundColor:[UIColor clearColor]];

    UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(137, 5, 255, 30)];
    [nameLabel setFont:[UIFont fontWithName:@"Arial" size:22.0f]];
    [nameLabel setText:[mo valueForKey:@"name"]];
    [nameLabel setTextAlignment:UITextAlignmentRight];
    [view addSubview:nameLabel];
    [nameLabel release];
    nameLabel = nil;
    ... Creating 20 or so label/imageviews all use 'mo' for data access to the NSManagedObject.

    [view.layer renderInContext:context];
    [view release];
    view = nil;
    //Get the result image
    resultImage = CGBitmapContextCreateImage(context);
    UIImage *viewImage = [UIImage imageWithCGImage:resultImage scale:0.0 orientation:UIImageOrientationUp];
    dispatch_async(dispatch_get_main_queue(),^ {
        [dataImageView setImage:viewImage];
    });

    //Cleanup
    free(bitmapData);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(resultImage);  
    CGContextRelease(context);
}); 

希望你们能帮助我,因为我无法理解这一点。我尝试使用 NSZombieEnabled YES 运行它,这有时会导致控制台出现以下错误-[UILabel hash]: message sent to deallocated instance 0x22841c00

【问题讨论】:

    标签: iphone multithreading cgcontext


    【解决方案1】:

    尝试调查此问题的可能根源: 当您创建 UILabel(s) 时,您将它们添加到 UIView 然后释放它们(没关系),但您也“无”它们。所以此时你有 UIView 保留的 UILabel 但同时它指向 nil! 所以最后,当你释放“视图”时,它会尝试释放它的子视图,并且一旦它遇到保留计数 = 1 但它已经为零的 UILabel,它就会得到“释放实例”异常。 这可以说明为什么调试器会在 [view release] 处停止,以及为什么 NSZombieEnabled 抱怨试图释放 UILabel:它认为它已释放,因为指针指向 nil。 所以可能的解决方案:删除“nameLabel = nil”语句。

    【讨论】:

    • 感谢您的回答,但起初我尝试不使用 nameLabel = nil;声明和结果是一样的,偶尔崩溃:(
    • 你没有将内存区域归零,只有指向内存区域的指针。视图会一直保留在内存中,直到所有对它的引用都被释放。
    猜你喜欢
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多