在后台线程上绘制上下文

发布于 2024-11-17 03:04:55 字数 3276 浏览 2 评论 0原文

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

下面的代码为我绘制了图形,但我偶尔会收到一些崩溃消息。通常 xcode 指向 [view release]; 并说 Thread 6: Program receive 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

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
    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);
}); 

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

对你而言 2024-11-24 03:04:55

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文