Ios 应用程序中的长时间运行任务:DidFinishLaunchSwithOptions:
我的应用程序中有一些长时间运行的启动任务(比如从本地数据存储加载解析对象)。这些任务应该在界面开始出现之前完成。该应用程序最初是使用故事板创建的,因此在Ios 应用程序中的长时间运行任务:DidFinishLaunchSwithOptions:,ios,multithreading,asynchronous,grand-central-dispatch,nsrunloop,Ios,Multithreading,Asynchronous,Grand Central Dispatch,Nsrunloop,我的应用程序中有一些长时间运行的启动任务(比如从本地数据存储加载解析对象)。这些任务应该在界面开始出现之前完成。该应用程序最初是使用故事板创建的,因此在应用程序:didFinishLaunchSwithOptions:方法完成后,界面开始自动显示。我无法阻止主线程,因为Parse SDK在主线程上触发所有回调(所以阻止会导致死锁)。我还需要延迟从application:DidFinishLaunchSwithOptions:返回以完成安装。所以我所做的是: - (BOOL)application
应用程序:didFinishLaunchSwithOptions:
方法完成后,界面开始自动显示。我无法阻止主线程,因为Parse SDK在主线程上触发所有回调(所以阻止会导致死锁)。我还需要延迟从application:DidFinishLaunchSwithOptions:返回以完成安装。所以我所做的是:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Dispatch long-running tasks
dispatch_group_t startup_group = dispatch_group_create();
dispatch_group_async(startup_group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Perform some long-running setup here
});
// Run main run loop until startup tasks finished (is it OK to do so?)
while (dispatch_group_wait(startup_group, DISPATCH_TIME_NOW))
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
return YES;
}
这是nsrunlop的正确用法吗?是否有任何潜在的警告?你能提出更优雅(最好是GCD)的解决方案吗
更新:
警告BlockingOperationMainThread
,因此UX不是问题UIApplication
delegate方法,这显然不是线程安全的虽然这在技术上取决于安装程序正在执行的操作(例如web服务调用),但应用程序可能永远不会启动或启动时出现意外结果
更为用户友好的方法是将一个“加载”视图控制器添加到您的故事板中,这将是您的着陆视图。在此处执行长时间运行的设置,同时向用户提供适当的信息/状态/任何信息,然后按下原始视图控制器。Imho我认为最好在主视图控制器中完成您的工作,并向用户显示:这样您就可以下载数据,用户就知道发生了什么
花这么长时间在一个空白屏幕上启动一个应用程序,或者只是在一个没有用户信息的屏幕上启动一个应用程序,这从来都不是一个好主意 延迟
didfishlaunchingwithoptions:
的返回确实是个坏主意。这会给你的应用留下坏印象,而且是个糟糕的设计
相反,您可以在视图控制器中着陆,并显示一个覆盖视图,该视图显示完成后正在执行的进度或活动,您可以将其取消。这是正确的方法
这是一个到第三方的库,可以轻松地显示/隐藏覆盖视图,并在视图上设置一些文本
你可以找到这么多这样的库,只需谷歌iOS HUD。HUD意味着平视显示,或者你可以自己使用UIAnimation
轻松设计定制的东西
一般来说,
我必须感谢您编写的代码,即您使用While
和nsrunlop
停止当前流或运行循环
可能您可以稍微修改代码,并在程序的其他位置使用它来停止当前流或运行循环并等待某些结果
NSDate *runloopUntill = [NSDate dateWithTimeIntervalSinceNow:0.1];
while (YourBoolFlag && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode runloopUntill])
以下apple文档将为您提供有关nsrunlop的深入见解,这是一个很有创意但非常糟糕的想法。您应该使UI加载处于故障保护状态—换句话说,假设网络不可用/速度慢,并显示一个视图,如果它在渲染之前没有获取数据,则该视图不会爆炸。然后,您可以安全地在后台队列中加载数据,并在加载完成后更新视图或转换到以数据为中心的视图
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
//Load your data here
//Dispatch back to the main queue once your data is loaded.
dispatch_async(dispatch_get_main_queue(), ^{
//Update your UI here, or transition to the data centric view controller. The data loaded above is available at the time this block runs
});
});
与其延迟返回带有选项的
didfishlaunchingwithoptions:
,我认为在主窗口前显示一个加载视图,告诉用户应用程序正在做什么是一个更好的主意。旋转运行循环可能存在的问题:您的解决方案可以在方法上做一些小的更改。我假设加载的对象是应用程序中共享状态的一部分。您只需添加一个ready
标志,在加载操作完成时设置true
。应用程序的其他部分可以重复检查此标志(使用NSTimer),或者您可以使用KVO或通知来获得完成通知。当涉及到UI时,尝试强制执行同步操作通常不是一个好主意。这可能是一个可行的解决方案,但它将后台逻辑与UI结合起来,这不是一个好主意。@allprog不确定你的意思,你能详细说明吗?给出的答案中没有一个能以我希望的方式真正解决这个难题,但是我承认所有的答案都是有用的,或多或少都是相似的,所以我决定把这个奖颁给最需要它的人。谢谢你们的时间和努力!谢谢!:)我希望你现在能以最好的方式解决你的问题@亚历山大·瓦塞宁-好消息:)