我有一个iPad应用程序,我想这样做
-(IBAction) clicked {
image=download(@"http://....."); // this is on the main thread
}
Run Code Online (Sandbox Code Playgroud)
下载功能将调用一大堆非阻塞函数从Internet下载文件,但下载本身不应该返回,直到下载图像.
当程序在上面的image = download(...)行等待下载时,我希望UI能够仍然运行,例如能够滚动UITableView,单击另一个按钮等.
所以我在下载函数中使用的是RunLoop
-(void) download:(NSString *)url
{
BOOL stillDownloading=TRUE;
while(stillDownloading) {
stillDownloading=downloadAFwBytes(...);
CFRunLoopRunInMode(kCFRunLoopCommonModes, 0, YES);
}
}
Run Code Online (Sandbox Code Playgroud)
我认为CFRunLoopRunInMode函数将继续抽取UI消息,触摸,滚动主UI线程,以便UI继续工作,直到下载完成后才冻结,但由于某种原因,它只能工作很短的时间,最终用户界面冻结.
你知道为什么,或者如何解决?
下载函数在程序中随处调用,期望它等待下载,因此我暂时无法将其更改为非阻塞.
你的问题的直接答案是,不,这不是什么CFRunLoopRunInMode.你有效地尝试做的是使当前的运行循环"产量",以便在加载操作继续时继续执行.这不是iOS和运行循环的工作方式.您的下载功能会阻止其下载的线程,直到下载完成为止,因此您的问题的唯一解决方案是更改实施,以便在后台线程上进行下载,并在完成时通知关注的对象.这是一个相对较小的变化,可以让你走上正确的轨道.这个整体主题(并发,管理后台任务)是一个更大的讨论,有不同的考虑/权衡.我会切入追逐,希望能让你走上正轨.
定义NSNotification一下你的下载方法可以发布感兴趣的对象观察的一对:
// in the .h file of the class performing the download
extern NSString * const MyClassLoadingDidStartNotification;
extern NSString * const MyClassLoadingDidFinishNotification;
// in the .m file of the class performing the download
NSString * const MyClassLoadingDidStartNotification = @"MyClassLoadingDidStart";
NSString * const MyClassLoadingDidFinishNotification = @"MyClassLoadingDidFinish";
Run Code Online (Sandbox Code Playgroud)在下载例程中,在后台进行下载并发布相应的通知:
-(void) download:(NSString *)url
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:MyClassLoadingDidStartNotification object:self];
BOOL stillDownloading=TRUE;
while(stillDownloading) {
stillDownloading=downloadAFwBytes(...);
}
[[NSNotificationCenter defaultCenter] postNotificationName:MyClassLoadingDidFinishNotification object:self];
});
}
Run Code Online (Sandbox Code Playgroud)在任何启动下载的对象中,观察并处理通知
// in any class that initiates a download
- (void)init...
{
self = [super init...];
if (self) {
// other initialization
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didStartLoading:) name:MyClassLoadingDidStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishLoading:) name:MyClassLoadingDidFinishNotification object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MyClassLoadingDidStartNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MyClassLoadingDidFinishNotification object:nil];
}
- (void)didStartLoading:(NSNotification *)notification
{
// update UI to show loading status (make sure you do UI changes on main thread)
// optionally check notification.object to ensure it's the loader class instance you care about
}
- (void)didFinishLoading:(NSNotification *)notification
{
// update UI to show loading status (make sure you do UI changes on main thread)
// optionally check notification.object to ensure it's the loader class instance you care about
}
Run Code Online (Sandbox Code Playgroud)请记住,这是一个非常基本的起点.随着您了解更多并决定您需要什么,您一定会定制它.例如,您可能希望添加错误处理,限制并发加载操作,提供其他加载状态等.
| 归档时间: |
|
| 查看次数: |
2079 次 |
| 最近记录: |