【问题标题】:Reload data of UITableView in background在后台重新加载 UITableView 的数据
【发布时间】:2013-06-25 05:58:01
【问题描述】:

在我的应用中,我有一个 UITableViewController。

它的tableView分为3个部分。

我从我的服务器下载每个部分的数据。为此,我有 3 个函数(例如 f1 f2 和 f3)。每个更新一个对应的 NSArray,用作我的表的数据源。

现在我想要的是使用这个函数重新加载数据并在这 3 个函数完成后刷新我的 tableView,但不会打扰用户。

我不使用异步请求、块、线程等......我正在寻找提示。

其实我就是这样做的:

-(void)viewDidLoad
{
    //some settings

    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(reloadDatas) userInfo:nil repeats:YES];

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        [self reloadDatas];
    });
}

-(void)reloadDatas
{
    dispatch_queue_t concurrentQueue = dispatch_get_main_queue();
    dispatch_async(concurrentQueue, ^{
        [self f1];
        [self f2];
        [self f3];
        [myDisplayedTable reloadData];
    });
}

-(void)f1
{
    //load datas with a url request and update array1
}
-(void)f2
{
    //load datas with a url request and update array2
}
-(void)f3
{
    //load datas with a url request and update array3
}

但是在这里,我的 tableView 被“冻结”直到它被刷新。

我不关心f1 f2和f3的执行顺序,但是我需要等待这3个函数完成后才能刷新我的tableView。

感谢您的帮助。

编辑

感谢您的所有回答。

这是可行的解决方案:

作为 mros 的建议,我从 viewDidLoad 中删除了调度队列,并在 reloadDatas 中替换:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

最后,我在主线程中重新加载表

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });

【问题讨论】:

    标签: ios asynchronous uitableview


    【解决方案1】:

    所以你的“后台线程”实际上是你的主线程。您必须使用 dispatch_get_global_queue 并指定优先级才能实际获得不同的线程。此外,viewDidLoad 中的异步调度是无用的,因为所有视图控制器生命周期方法都在主线程中调用。我建议在您的 f1、f2 和 f3 方法中执行以下操作:

    首先启动一个异步 url 请求,然后在完成块中,更新 arrayX 并重新加载 tableview 的特定部分。这样,所有三个请求都可以同时发生,并且表只会在每个请求完成时更新必要的数据。或者,如果您只想重新加载一次,只需将您拥有的 concurrentQueue 变量替换为后台线程,然后在主线程上执行 [tableView reloadData]

    【讨论】:

      【解决方案2】:

      前面的答案是绝对正确的。但是,您的 reloadDatas 和 viewDidLoad 实现有点问题。

      澄清一下:

      您想在后台线程中完成耗时的数据加载工作,然后在主线程上准备好数据时更新 UI/Cells。

      像这样:

        -(void)viewDidLoad
          {
             dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.backgroundQueue", NULL);
              dispatch_async(concurrentQueue, ^{
                  [self reloadDatas];
              });
          }
      
      -(void)reloadDatas
      {
          // Expensive operations i.e pull data from server and add it to NSArray or NSDictionary
            [self f1];
            [self f2];
            [self f3];
      
          // Operation done - now let's update our table cells on the main thread  
      
          dispatch_queue_t mainThreadQueue = dispatch_get_main_queue();
          dispatch_async(mainThreadQueue, ^{
      
              [myDisplayedTable reloadData]; // Update table UI
          });
      }
      

      【讨论】:

      • 我已经尝试了您的解决方案,但用户交互和重新加载相互阻止。我的意思是 reloadDatas 没有被调用,因为用户没有停止滚动表格,并且在表格没有刷新时用户无法滚动表格......
      • 您确定它没有被调用,因为用户正在滚动表格吗?尝试添加一些 NSLog 或断点。
      • 是的,这就是user interactions 的意思:滚动表格时,我的 NSTimer 直到滚动结束才会调用我的函数。
      • 为什么首先使用计时器?我为你添加了另一个答案
      • 很有帮助!谢谢
      【解决方案3】:

      另一件事。从服务器提取数据并更新表格单元格是很常见的。 这里不需要队列或计时器。 这是另一种结构。

      假设您正在从服务器中提取 mp3: 您的模型类是:Music.h/m 您的模型管理器是: MusicManager.h/m (Singleton) - 它将包含一系列音乐对象 - 单例基本上是您的数据源; 最后是你的 UItableViewController : MusicTableVC.h/m

      在 MusicManager.h/m 中:您有一个 NSMutableArray,它将加载您从服务器拉取的 Music.h 对象。您可以在应用加载后立即执行此操作,甚至无需等待 TableViewController。

      在 MusicManager 中,您有一些辅助方法可以在 mutableArray 中添加或删除项目,并提供计数,当然还有您的网络方法。

      最后:在您的网络代码中发布通知。您的 UITableViewController 应该监听/观察该通知并相应地“重新加载”。

       [[NSNotificationCenter defaultCenter] postNotificationName:@"NewMusicAdded" object:nil];
      

      您从服务器查询数据,将数据解析为 Music 对象,将它们添加到您的 NSMutable 数组并发布通知以让表自行更新。

      相当标准的食谱。

      【讨论】:

        【解决方案4】:

        reloadDatas 方法中你应该改变这一行:

        dispatch_queue_t concurrentQueue = dispatch_get_main_queue();
        

        收件人:

        dispatch_queue_t concurrentQueue = dispatch_queue_create("some queue", NULL);

        但是当你调用[myDisplayedTable reloadData]时,你需要在主队列中调用这个操作。

        dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });
        

        【讨论】:

        • 你创建了 concurrentQueue 吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-31
        • 2013-11-13
        • 1970-01-01
        • 2012-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多