ios - 如何实现延迟json文件下载?

标签 ios json lazy-evaluation

我正在使用一个 Web 服务,它从我服务器上的数据库返回一个 JSON 格式的数据,这些数据将显示在我的 iPhone 应用程序的某个 View 中。

由于该应用程序是免费的,所以我在我的数据库中获得了数千行,当然我必须下载 JSON 数据。

如何对我的 JSON 数据进行延迟加载?请任何代码行将不胜感激。

谢谢。

编辑 1:

换句话说,我正在使用 Sql 请求,例如“从表中选择所有内容”,然后将此数据作为 JSON 返回到我的应用程序。

我怎样才能请求一个小数字然后添加其他人等..?

最佳答案

术语“延迟加载”可能并不完全适合单个 JSON 响应,它可能使我们倾向于采用一种方法而不是另一种方法。因此,让我解决我认为的潜在问题,即尽管服务器数据库非常大,但您仍希望获得改进的用户体验:

  • 如果 JSON 真的很大,你总是可以考虑一个“分页”比喻,在那里你下载前 x 条记录,然后对服务器数据的下一个“页面”发出后续请求。鉴于可能会在请求之间添加额外的服务器记录,您必须仔细考虑该实现,但这可能很容易做到。
  • 另一种使 JSON 更高效的方法是限制初始请求中返回的数据。例如,第一个请求可以只返回所有记录或合理子集的标识符或 header 信息,然后您可以有后续请求以获取其他详细信息(例如,用户转到详细信息屏幕)。
  • 先前点的一个特定排列是 JSON 当前是否包含任何大型数据元素(例如 Base64 编码的二进制数据,如图像或声音文件)。通过将这些从最初的回应中剔除,这将解决许多问题。如果您可以返回此二进制数据的 URL,而不是数据本身,那么这肯定会适合延迟加载(以及让您能够轻松下载二进制信息,而不是大 33% 的 Base64 编码) .如果您正在处理图像,您可能还需要考虑缩略图与大图像的想法,尤其是在延迟加载模型中处理后者。
  • 您可以考虑实现支持流的 XML 解析版本。标准NSXMLParser在解析进行之前,实现尝试一次将整个 XML 提要(或尽可能多地?)加载到内存中(尽管方法名称会暗示相反)。如果您的应用使用了 LibXML2 (例如在 Apple 的 AdvancedURLConnections sample 中),您可以在向用户呈现初始数据的同时继续在后台下载和解析 XML。这将同时产生大多数人与“延迟加载”(即在将结果呈现给用户之前不等待所有内容)和“急切加载”(即它将下载下一条记录,以便它们当他们去那里时已经为用户准备好了)。

  • 为了让我们提出更明智的建议,您确实需要分享更多关于 JSON 的性质及其背后数据的信息,描述为什么您认为“延迟加载”是解决方案等。您可能不想在特定的解决方案,直到您对数据进行一些分析(例如,数千行的 JSON 仍然可以小于单个大图像)。

    更新:

    如果您打算采用第一种方法,您首先需要更改您的 Web 服务,以便响应请求,它只提供 n 条记录,从特定的记录号开始。您可能还需要返回服务器上的总记录数,以便您可以向用户提供一些关于要滚动多少的视觉提示。

    其次,您需要更新您的 iOS 应用程序以支持此模型。因此,在您的 UI 中,当您滚动浏览结果时,您可能希望您的用户界面通过显示 (a) 实际结果(如果您已经获取它)来响应滚动事件;或 (b) 一些 UI,它在视觉上指示正在检索相关记录,然后从服务器异步请求信息。如果您在 UITableViewCell 中执行此操作,它可能会执行以下操作:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [self initiateRequestForFirstSetOfData];
    }
    
    - (void)initiateRequestForFirstSetOfData
    {
        // asynchronously retrieve the data from the server:
        //   (a) retrieve the total number of records
        //   (b) retrieve the actual data for the first n records
        // and when this is done, dispatch a `[self.tableView reloadData]` back to the
        // main queue.
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.totalNumberOfRecordsOnServer;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
        BOOL isAvailable = ... // do whatever logic to determine if this row has already been retrieved
    
        if (isAvailable)
        {
            // configure the cell like normal here
        }
        else
        {
            // configure the cell to indicate that a fetch is in progress here.
    
            // perhaps add a UIActivityIndicatorView and startAnimating it
    
            dispatch_async(backgroundQueue, ^{
    
                // initiate the request for the data (if you haven't already)
    
                dispatch_async(dispatch_get_main_queue(), ^{
    
                    // don't just update the UI here, but make sure the cell
                    // in question is still on screen by calling `UITableView`
                    // method `cellForRowAtIndexPath`, not to be confused with
                    // this method, which is a `UITableViewController` method.
    
                    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
                    if (cell)
                    {
                        // update the cell: sometimes you can get away with
                        // updating the cell directly, sometimes you want to
                        // just call something like:
                        //
                        // [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    }
                });
            });
        }
    
        cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
    
        return cell;
    }
    

    我可能会建议对上面的代码进行大量改进,相当简单的代码,但希望它能为您提供基本的想法。你 (a) 算出总共有多少行数据; (b) 您检索前 n 条记录; (c) 当用户滚动到一条记录时,如果你有它,你就显示它,但如果没有,提供视觉提示,你将异步地为他们获取该数据; (d) 当数据进入时,如果合适,更新 UI。

    就像我说的那样,我可能会对上述代码进行一些改进,例如,我可能不会将异步检索嵌入到 View Controller 本身中,而是在我的模型中执行此操作并使用一些委托(delegate)模式来更新 UI,我可能会使用操作队列而不是调度队列,这样我就可以取消我们不再需要的请求,等等,但你明白了基本的想法。

    如果您使用的是 UICollectionViewController ,类似于上面的代码。如果您使用 ScrollView ,模式非常相似,尽管您会响应 UIScrollViewDelegate方法 scrollViewDidScroll取而代之(您不仅需要像上面那样编写代码,还需要编写一些可以释放 UIKit 已滚出屏幕的元素的代码)。

    关于ios - 如何实现延迟json文件下载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13980386/

    相关文章:

    jpa-2.0 - 使用 JPA 加载懒惰 vs 急切加载

    ios - 如何在 swift 中实现 UICollectionView 的瀑布布局,根据获取的远程图像改变它们的高度?

    javascript - 根据参数字符串值显示 JSON 值

    iphone - 如何隐藏UITableView中的行分隔符而不隐藏组边框?

    javascript - 在 Angular js 中打印 JSON,我可以在控制台中看到,但无法打印相同的内容

    android - 使用 REST 发送和接收复杂数据

    haskell - 为什么这不能在恒定内存中运行?

    parsing - 应用解析器陷入无限循环

    ios - 快速设置 Root View Controller 时删除新创建的导航栏

    ios - objective-c 中的箭头运算符