简体   繁体   English

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

[英]Performing many UIKit operations blocking main thread

when the app is launched, I'm programmatically creating many complex UIViews with transparent background colour, each being a 'screen' in the app (has to be this way since there's animated background underneath). 当应用程序启动时,我会以编程方式创建许多具有透明背景颜色的复杂UIViews,每个都是应用程序中的“屏幕”(必须是这样的,因为下面有动画背景)。 This causes the app to stay on the static launch image for quite long (about 4 seconds). 这会导致应用程序在静态启动映像上停留很长时间(大约4秒)。

I would like to create all the UIViews while an animation is shown. 我想在显示动画时创建所有UIViews。 I can't create UIViews on background thread. 我无法在后台线程上创建UIViews。 How can I accomplish this? 我怎么能做到这一点?

Attempt 1: 尝试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];
        });

    });
}

The button is added, but the title is never set. 添加了按钮,但从未设置标题。 It appears after tapped. 点击后显示。

UIViews are not thread safe in normal usage, and all interaction should occur on the main thread. UIViews在正常使用中不是线程安全的,并且所有交互都应该在主线程上发生。 That said, you should be able to, on some background thread (dispatch queue), create the view, modify its parameters, set complex background colors, etc - as long as the view is not connected to anything (and thus receiving events from iOS). 也就是说,你应该能够在一些后台线程(调度队列)上创建视图,修改其参数,设置复杂的背景颜色等 - 只要视图没有连接任何东西(从而接收来自iOS的事件) )。 Once the view is completely setup and wired, then dispatch a block with it to the main queue and only then add it as a subview to some other view. 一旦视图完全设置并连线,然后将一个块分配给主队列,然后将其作为子视图添加到其他视图中。

What I would do is dispatch all this work to the normal priority queue after having set up my initial video clip. 我要做的是在设置我的初始视频剪辑后将所有这些工作分配到普通优先级队列。 When all the views have been posted back to the main queue (and thus this work is complete), you can stop the video and start interacting with the user. 当所有视图都已回发到主队列(因此​​此工作已完成)时,您可以停止视频并开始与用户交互。

Thanks for help. 感谢帮助。 Here's the final solution that I tested and works perfectly. 这是我测试并完美运行的最终解决方案。

I created a task manager class, FCTaskManager: 我创建了一个任务管理器类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

Then I can use the task manager like so: 然后我可以这样使用任务管理器:

-(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];
    }];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM