后台获取不更新 UI

Posted

技术标签:

【中文标题】后台获取不更新 UI【英文标题】:Background fetch not updating UI 【发布时间】:2014-02-18 16:37:26 【问题描述】:

我是 ios7 后台获取的新手。这是我的做法。

这就是appDelegate中发生的事情:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

NSURL *url = [[NSURL alloc] initWithString:@"http://sample.com/api/home/lastnews"];
OldJson = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

请注意,这里我将整个 JSON 文件存储在一个字符串中,以便我可以使用它来检查新内容。

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

//HomepageView is the view controller that is supposed to be updated
HomepageView *homepage = [[HomepageView alloc] init];

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];

NSURL *url = [[NSURL alloc] initWithString:@"http://sample.com/api/home/lastnews"];
NewJson = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

NSURLSessionDataTask *task = [session dataTaskWithURL:url
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 

    if (error) 
        completionHandler(UIBackgroundFetchResultFailed);
        return;
    

    if (![NewJson isEqualToString:OldJson])
    
        completionHandler(UIBackgroundFetchResultNewData);
        NSLog(@"New Data : %@",NewJson);
    
    else
    
        completionHandler(UIBackgroundFetchResultNoData);
        NSLog(@"Old Json : %@",OldJson);
    
];

// Start the task
[task resume];

现在要测试整个过程,我只需运行应用程序。然后我将它发送到后台,然后当我在 JSON 文件中有新内容时,我使用 Debug 菜单中的 Simulate Background Fetch 操作。然后我打开应用程序,但没有任何改变。

【问题讨论】:

您在完成处理程序中得到了什么? 一件事:只有主线程才能修改UI。 @CW0007007 你是什么意思? @Larme 好的,这是否意味着我无法更新 appdelegate 中的 UI?那么后台抓取有什么意义呢? 您可以通过后台获取数据并通知主线程上的处理程序需要更新。有几种方法可以做到,我喜欢用 NSNotificationCenter:developer.apple.com/library/ios/documentation/Cocoa/Reference/… 【参考方案1】:

首先将您的 newJson 存储在 NSUserDefaults 中,如下所示

    if (![NewJson isEqualToString:OldJson])
                       
                         completionHandler(UIBackgroundFetchResultNewData);
                         NSLog(@"New Data : %@",NewJson);
                         NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
                         [defaults setObject:NewJson forKey:@"newJson"];

                      

第二个在你的视图控制器中添加这个ViewDidLoad

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refresh:) name: UIApplicationWillEnterForegroundNotification object:nil];

将此添加到您的viewWillAppear

-(void)viewWillAppear:(BOOL)animated
[self loadData];


创建负载数据

- (void)loadData 
    // contains information the ViewController makes use of

    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    textView.text =  [defaults objectForKey:@"newJson"];

最后添加您的操作

-(IBAction)refresh:(id) sender 
    NSLog(@"I ran");
    [self loadData];

我对此进行了测试,它确实有效。

【讨论】:

这是错误的。在 iOS9.3 上,这将导致警告说:“此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃。这将在未来的版本中导致异常。”【参考方案2】:

三个问题:

    无法保证 JSON 数据采用 UTF-8 格式。使用 [NSData dataWithContensOfURL:...]

    永远不要从主线程访问 URL。如果服务器没有响应,您的应用程序将挂起。

    非常糟糕:在您的后台获取处理程序中,您实际上是同步加载 URL。 然后你创建一个任务来再次加载它。所以你实际上加载了两次。

【讨论】:

以上是关于后台获取不更新 UI的主要内容,如果未能解决你的问题,请参考以下文章

在添加到视图之前在后台线程中更新 UI 元素

iOS中的后台获取

winform 后台线程更新UI

WPF:在后台不断更新 UI

从后台任务中更新android UI

swift3 - 使用后台数据更新 ui