执行许多阻止主线程的UIKit操作

时间:2013-07-24 17:47:35

标签: ios objective-c multithreading uiview uikit

当应用程序启动时,我会以编程方式创建许多具有透明背景颜色的复杂UIView,每个都是应用程序中的“屏幕”(必须是这样的,因为下面有动画背景)。这会导致应用程序在静态启动图像上停留很长时间(约4秒)。

我想在显示动画时创建所有UIViews。我无法在后台线程上创建UIViews。我怎么能做到这一点?

尝试1:

-(void)viewDidLoad {

    [super viewDidLoad];


    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        UIView *baseView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 200, 100)];
        [baseView setBackgroundColor:[UIColor blueColor]];

        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 180, 80)];
        [button setBackgroundColor:[UIColor redColor]];
        [button setTitle:@"button" forState:UIControlStateNormal]; //doesn't work
        [baseView addSubview:button];

        dispatch_async( dispatch_get_main_queue(), ^{ //Finished

            [self.view addSubview:baseView];
        });

    });
}

添加了按钮,但从未设置标题。点击后显示。

2 个答案:

答案 0 :(得分:2)

UIViews在正常使用中不是线程安全的,并且所有交互都应该在主线程上发生。也就是说,你应该能够在一些后台线程(调度队列)上创建视图,修改其参数,设置复杂的背景颜色等 - 只要视图没有连接任何东西(从而接收来自iOS的事件) )。一旦视图完全设置并连线,然后将一个块分配给主队列,然后将其作为子视图添加到其他视图中。

我要做的是在设置了我的初始视频片段后将所有这些工作分配到普通优先级队列。当所有视图都已回发到主队列(因此​​这项工作已完成)时,您可以停止视频并开始与用户进行交互。

答案 1 :(得分:2)

感谢您的帮助。这是我测试并完美运行的最终解决方案。

我创建了一个任务管理器类FCTaskManager:

//Header File

typedef void (^TaskBlock)(void);
typedef void (^TaskCompletedBlock)(void);

@interface FCTaskManager : NSObject

-(void)performUITask:(TaskBlock)taskBlock completionBlock:(TaskCompletedBlock)taskCompletedBlock;
-(void)performBackgroundTask:(TaskBlock)taskBlock completionBlock:(TaskCompletedBlock)taskCompletedBlock;

@end



//Implementation

#import "FCTaskManager.h"

@implementation FCTaskManager

-(void)performUITask:(TaskBlock)taskBlock completionBlock:(TaskCompletedBlock)taskCompletedBlock {

    dispatch_async( dispatch_get_main_queue(), ^{

        @autoreleasepool {

            taskBlock();

            dispatch_async( dispatch_get_main_queue(), ^{

                taskCompletedBlock();
            });
        }
    });
}

-(void)performBackgroundTask:(TaskBlock)taskBlock completionBlock:(TaskCompletedBlock)taskCompletedBlock {

    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        @autoreleasepool {

            taskBlock();

            dispatch_async( dispatch_get_main_queue(), ^{

                taskCompletedBlock();
            });
        }
    });
}

@end

然后我可以像这样使用任务管理器:

-(void)viewDidLoad {

    [super viewDidLoad];

    //Create taskManager
    taskManager = [[FCTaskManager alloc] init];

    //Create UIViews, etc WITHOUT blocking main queue
    [taskManager performUITask:^{

        button = [[UIButton alloc] initWithFrame:CGRectMake(30, 30, 300, 300)];
        [button setBackgroundColor:[UIColor redColor]];
        [button setTitle:@"Working" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];

    } completionBlock:^{

        NSLog(@"CREATED BUTTON");

        [self.view addSubview:button];
    }];
}