首页 iOS.& Swift Books uikit学徒

35
异步网络 由Matthijs Hollemans撰写& Fahim Farook

您已收到您的应用程序正在进行网络搜索,它正在运行。同步网络呼叫不是那么糟糕,是吗?

是的,他们是,我会告诉你为什么!您是否注意到,每当您执行搜索时,该应用程序都没有响应?虽然网络请求发生,但您无法向上或向下滚动表视图,或在搜索栏中键入新的内容。该应用程序完全冻结几秒钟。

如果您的网络连接非常快,您可能没有看到此功能,但如果您在野外使用iPhone,网络将比您的家庭或办公Wi-Fi慢得多,并且搜索可以轻松花费秒或更长时间。

对于大多数用户来说,一个没有响应的应用程序是一个崩溃的应用程序。用户可能会按下主页按钮,然后重试 - 或更有可能,删除您的应用,使其在App Store上的糟糕评分,并切换到竞争的应用程序。

因此,在本章中,您将学习如何使用异步网络来消除UI响应问题。你会做以下事项:

  • 极端同步网络: 了解如何通过拨打同步网络到最大值来影响应用程序的性能。
  • 活动指标: 添加活动指示灯以显示搜索何时进行,以便用户知道某些事情正在发生。
  • 使它异步: 更改Web服务请求的代码以在后台线程上运行,以便它不会锁定应用程序。

极端同步网络

仍然没有说服同步网络的邪恶?让我们减慢网络连接,假装应用程序在iPhone上运行,即某人可以在公共汽车上或火车上使用,而不是在快速家庭或办公网络的理想条件下。

首先,您将增加应用程序接收的数据量 - 通过向URL添加“限制”参数,您可以设置Web服务将返回的最大结果数。默认值为50,最大值为200。

➤打开 searchViewController.swift. and in iTunesURL(searchText:), change the line with the web service URL to the following:

let urlString = String(format: 
  "//itunes.apple.com/search?term=%@&limit=200", 
  encodedText)

You added &limit=200 to the URL. Just so you know, parameters in URLs are separated by the & sign, also known as the “and” or “ampersand” sign.

➤如果您现在运行应用程序,搜索应该有点慢。

网络链接调节器

您还是太快了解任何应用响应问题?然后用来 网络链接调节器。这是Apple提供的额外开发人员工具,允许您模拟不同的网络条件,如坏手机网络,以便测试您的iOS应用程序。

更多开发人员工具菜单选项
MKU ViroTusizucih Saiqc Zuyo Uzveoh

APple Developers页面的下载
GSA XIFQDIUDH FID ILBTA WEBIGOPEWJ CITE

网络链接调节器偏好窗格
SCI Depqujm Xeety Nahyafiedaj Rdujevedba Guja

添加配置文件以获得非常慢的连接
OHTUCC KQO BQEWOZI LUP e PEQL KROL QUBVUQNOOB

设备条件

网络链接调节器适用于模拟器上减慢下载并模拟网络条件差的下载。但它不适用于实际设备。如果有一种方法可以在实际设备上模拟网络条件吗?

设置设备的网络链路条件
Cartejy waswuql cehp jotyapeocd xux dajoli

活动指标

您是否注意到该应用程序在搜索操作期间如何响应如何?感觉就像错了。应用程序是否崩溃或仍在做某事?当发生这种情况时,不可能告诉你的用户是不可能的。

该应用程序显示它很忙
LDU OPV WZICW LROZ AG IX MEPZ

活动指示符表视图单元格

➤创建一个新的空的nib文件。称它为 loadingcell.xib..

Loadingcell嘴唇的设计
yji muqipv aw Jwa Ruofepjzolk Gef

使用活动指示单元格

要显示此特殊表视图单元格,您将遵循与“未找到”单元格相同的步骤。

static let loadingCell = "LoadingCell"
cellNib = UINib(
  nibName: TableView.CellIdentifiers.loadingCell, 
  bundle: nil)
tableView.register(
  cellNib, 
  forCellReuseIdentifier: TableView.CellIdentifiers.loadingCell)
var isLoading = false
func tableView(
  _ tableView: UITableView, 
  numberOfRowsInSection section: Int
) -> Int {
  if isLoading {
    return 1
  } else if !hasSearched {
    . . . 
  } else if . . . 
func tableView(
  _ tableView: UITableView, 
  cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
  // New code 
  if isLoading {
    let cell = tableView.dequeueReusableCell(
      withIdentifier: TableView.CellIdentifiers.loadingCell, 
      for: indexPath)
        
    let spinner = cell.viewWithTag(100) as! UIActivityIndicatorView
    spinner.startAnimating()
    return cell
  } else 
  // End of new code
  if searchResults.count == 0 {
    . . .
func tableView(
  _ tableView: UITableView, 
  willSelectRowAt indexPath: IndexPath
) -> IndexPath? {
  if searchResults.count == 0 || isLoading {    // Changed
    return nil
  } else {
    return indexPath
  }
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
  if !searchBar.text!.isEmpty {
    searchBar.resignFirstResponder()
    // New code
    isLoading = true                    
    tableView.reloadData()
    // End of new code
    . . .
    isLoading = false                     // New code
    tableView.reloadData()
  }
}

测试新的加载单元

➤运行应用程序并执行搜索。虽然搜索正在进行载入......具有纺纱活动指示器的细胞应该出现......

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
  if !searchBar.text!.isEmpty {
    searchBar.resignFirstResponder()
    isLoading = true
    tableView.reloadData()
    /*
       . . . the networking code (commented out) . . . 
     */
  }
}

主线程

CPU(C舍如内 P陶瓷 U在最古老的iPhone和iPad模型中有一个核心,这意味着它一次只能做一件事。后来的模型有一个带有两个核心的CPU,这允许同时发生两种计算。最新的Apple Mobile CPU有六个核心。

使它异步

为防止阻止主线程,任何可能需要一段时间的操作应该是 异步。这意味着操作发生在后台线程中,并且在平均时间内,主线程可以自由处理新事件。

队列有一个关闭在后台线程上的封闭列表
Quuein Kera o Kurk在Mxosolen Fu Rigvavj Ad A Vizjdheayr VQQUUJ

将Web请求放在后台线程中

To make the web service requests asynchronous, you’re going to put the networking part from searchBarSearchButtonClicked(_:) into a closure and then place that closure on a medium priority queue.

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
  if !searchBar.text!.isEmpty {
    . . .
    searchResults = []
    // Replace all code after this with new code below
    // 1
    let queue = DispatchQueue.global()
    let url = self.iTunesURL(searchText: searchBar.text!)
    // 2
    queue.async {
      
      if let data = self.performStoreRequest(with: url) {
        self.searchResults = self.parse(data: data)
        self.searchResults.sort(by: <)
        // 3
        print("DONE!")
        return
      }
    }
  }
}

将UI更新放在主线程上

我从闭包中删除了所有用户界面代码的原因 - 然后移动获取关闭外部的搜索网址 - 是uikit有一个规则,即UI代码应该 总是 在主线程上进行。这个很重要!

DispatchQueue.main.async {
  self.isLoading = false
  self.tableView.reloadData()
}

各种队列

使用GCD队列时,您通常会看到此模式:

let queue = DispatchQueue.global()
queue.async {
  // code that needs to run in the background
  
  DispatchQueue.main.async {
    // update the user interface
  }
}

主线程检查器

我之前提到过,Wo不需要在后台线程上运行UI代码。然而,直到一个FOV是啊,试图在后台螺纹上跑来努力。

编辑方案
agum cggiti.

主线程检查器设置
Couf dfleas txijgit cawsemv

let url = self.iTunesURL(searchText: searchBar.text!)
queue.async {
    let url = self.iTunesURL(searchText: searchBar.text!)
    ...
} 
Main Thread Checker: UI API called on a background thread: -[UISearchBar text]
PID: 42716, TID: 13711829, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4   StoreSearch                         0x00000001032b60e5 $s11StoreSearch0B14ViewControllerC09searchBarB13ButtonClickedyySo08UISearchF0CFyycfU_ + 325
5   StoreSearch                         0x00000001032b6890 $sIeg_IeyB_TR + 48
6   libdispatch.dylib                   0x000000010356d8ac _dispatch_call_block_and_release + 12
7   libdispatch.dylib                   0x000000010356ea88 _dispatch_client_callout + 8
8   libdispatch.dylib                   0x0000000103570f06 _dispatch_queue_override_invoke + 1032
9   libdispatch.dylib                   0x00000001035805b6 _dispatch_root_queue_drain + 351
10  libdispatch.dylib                   0x0000000103580f1b _dispatch_worker_thread2 + 135
11  libsystem_pthread.dylib             0x00007fff5dd919f7 _pthread_wqthread + 220
12  libsystem_pthread.dylib             0x00007fff5dd90b77 start_wqthread + 15
2020-08-21 12:07:41.077485-0400 StoreSearch[42716:13711829] [reports] Main Thread Checker: UI API called on a background thread: -[UISearchBar text]
PID: 42716, TID: 13711829, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4   StoreSearch                         0x00000001032b60e5 $s11StoreSearch0B14ViewControllerC09searchBarB13ButtonClickedyySo08UISearchF0CFyycfU_ + 325
5   StoreSearch                         0x00000001032b6890 $sIeg_IeyB_TR + 48
. . .
表示主题检查器问题的紫色图标
lupqdu uvevn apjimodaxt juel pwsiaq nlussub ipreik

发行导航员
enria cusemiiviv.

提交您的代码

➤我认为通过这一重要的改进,该应用值得新的版本号。因此提交更改并创建标签 v0.2。您将必须执行此操作作为两个单独的步骤 - 首先使用合适的消息创建提交,然后为最新提交创建标记。

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里.

有反馈分享在线阅读体验吗? 如果您有关于UI,UX,突出显示或我们在线阅读器的其他功能的反馈,您可以将其发送到设计团队,其中表格如下所示:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。