开发者

Drawing to context on background thread

开发者 https://www.devze.com 2023-03-15 12:07 出处:网络
I have a UIView which has to display some information. Since this view is quite complex and the drawing takes a substantial amount of time, I have moved this to a background thread to avoid blocking t

I have a UIView which has to display some information. Since this view is quite complex and the drawing takes a substantial amount of time, I have moved this to a background thread to avoid blocking the main thread. When the drawing is done, I dispatch back to the main thread to set the ImageView.

The following code does the drawing for me, but i receive some occasional crashes. Usually xcode points at [view release]; and says 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
    c开发者_StackOverflow社区ontext = 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);
}); 

Hope you guys can help me, because I cant make heads or tail of this. I have tried to run it with NSZombieEnabled YES which some times resulted in the following error in the console -[UILabel hash]: message sent to deallocated instance 0x22841c00


Try to investigate this possible source of the issue: when you create the UILabel(s) you add them to the UIView and then you release them (it's OK) but you also "nil" them. So at this point you have the UILabel which is retained by the UIView but at the same time it points to nil! So at the end when you release "view" it will try to release its subviews, and as soon as it encounters the UILabel which has retain count = 1 but it has been nil'd it gets the "deallocated instance" exception. This can demonstrate why the debugger stops at [view release] and why NSZombieEnabled complains for trying to deallocate the UILabel: it sees it as deallocated as the pointer points to nil. So possible solution: remove the "nameLabel = nil" statement.

0

精彩评论

暂无评论...
验证码 换一张
取 消