使用Swift在iOS上使用Internet连接:最佳实践

Networking is an integral part of most iOS applications. A common network-related task is Internet connectivity detection. Typically, it appears in three scenarios:

网络是大多数iOS应用程序不可或缺的一部分。 与网络相关的常见任务是Internet连接检测。 通常,它出现在三种情况下:

  • Checking connectivity before firing an HTTP request.

    在触发HTTP请求之前检查连接性。
  • Disabling or enabling app features based on network connectivity status.

    根据网络连接状态禁用或启用应用程序功能。
  • Attaching constraints to network operations, e.g., disabling large file download via cellular.

    将约束附加到网络操作上,例如,禁止通过蜂窝网络下载大文件。

The most popular answers on how to detect network connectivity status on iOS suggest using SCNetworkReachability. In this article, let's discuss why this solution is less than optimal, and lay out best practices of working with the Internet connection recommended by Apple.

关于如何在iOS上检测网络连接状态的最流行的答案是建议使用SCNetworkReachability 。 在本文中,我们将讨论为什么此解决方案不是最佳解决方案,并列出了使用Apple推荐的Internet连接的最佳实践。

在发出请求之前检查连接性 (Checking Connectivity Before Firing a Request)

In its documentation, Apple says that we should not check Internet connection before firing an HTTP request. From Networking Overview:

苹果在其文档中表示, 触发HTTP请求之前 ,我们不应该检查Internet连接。 从网络概述

The SCNetworkReachability API is not intended for use as a preflight mechanism for determining network connectivity. [...]

SCNetworkReachability API不能用作确定网络连接的预检机制。 [...]

We can hear similar pieces of advice in multiple WWDC sessions. From Advances in Networking, Part 1, at 50:00:

我们可以在多个WWDC会议中听到类似的建议。 摘自网络进步,第1部分 ,在50:00:

Pre-flight check is a very bad indicator of where your flow will end up on.

飞行前检查是非常糟糕的指示器,指示您的流量将最终流向何处。

From Advances in Networking, Part 2, at 56:00

摘自网络进步,第2部分 ,在56:00

Pre-flight checks have inherited race conditions.

飞行前检查继承了比赛条件。

From Networking Best Practices, at 33:00:

网络最佳实践 ,于33:00:

Don’t check the Reachability object to determine whether something is available. It can be deceptive in some cases.

不要检查“可达性”对象来确定是否有可用的对象。 在某些情况下可能具有欺骗性。

The reasons for these statements are next:

这些语句的原因如下:

  • Knowing in advance how Wi-Fi will perform until you try is impossible [Advances in Networking, Part 2, 57:00].

    事先不知道Wi-Fi的性能,直到您尝试为止是不可能的[ 网络高级知识,第2部分 ,57:00]

  • Internet connection pre-flight checks have inherent race conditions, give false positives and false negatives, time-of-check to time-of-use problem [Apple dev forum thread].

    互联网连接飞行前检查具有固有的竞争条件, 对使用时间问题给出假阳性和假阴性, 检查时间 [ Apple dev论坛主题 ]

  • Reachability will report unreachable if the networking hardware is powered down. Attempting to make a connection will power up the networking hardware. If you are relying on Reachability (or NWPathMonitor - addition mine) saying something might be reachable, you are relying on something else (a background process) powering up the networking hardware [AFNetworking GitHub thread].

    如果网络硬件已关闭,则可达性将报告无法访问。 尝试建立连接将打开网络硬件的电源。 如果您依靠“可达性”(或NWPathMonitor - NWPathMonitor mine )说可能可以实现某些目标,则您是在依靠其他(后台进程)来为网络硬件加电[ AFNetworking GitHub线程 ]

The solution is to use Adaptable Connectivity APIs. By opting in to this feature, we tell URLSession that it should wait for a connection to the server instead of failing a URLSessionTask because of a lack of connectivity.

解决方案是使用Adaptable Connectivity API 。 通过选择使用此功能,我们告诉URLSession它应该等待与服务器的连接,而不是由于缺乏连通性URLSessionTask失败。

All it takes to enable Adaptable Connectivity is to set waitsForConnectivity flag on URLSessionConfiguration:

它所需要的,使适应连接是设置waitsForConnectivityURLSessionConfiguration

let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
config.timeoutIntervalForResource = 300let session = URLSession(configuration: config)let url = URL(string: "https://www.example.com/")!
session.dataTask(with: url) { data, response, error in
// ...
}

Now we are all set. If a device is online, HTTP requests will fire immediately. Otherwise, URLSession will wait until the device is connected to the Internet, and then fire a request.

现在我们都准备好了。 如果设备在线,HTTP请求将立即触发。 否则, URLSession将等到设备连接到Internet后再发出请求。

By default, URLSession waits for the Internet connection for up to 7 days. If this is not the behavior you want, you could set timeoutIntervalForResource to a relevant value.

默认情况下, URLSession等待Internet连接最多7天。 如果这不是您想要的行为,则可以将timeoutIntervalForResource设置为相关值。

基于Internet连接启用或禁用应用程序功能 (Enabling or Disabling App Features Based on Internet Connection)

Same as with pre-flight checks, enabling or disabling app features based on an Internet connection is discouraged. The reason for this is that we cannot reliably check connectivity status via Reachability or NWPathMonitor:

与飞行前检查相同,不鼓励基于Internet连接启用或禁用应用程序功能。 原因是我们无法通过Reachability或NWPathMonitor可靠地检查连接状态:

  • The Wi-Fi signal could disappear after your app checks reachability, but before it connects [Networking Overview].

    在您的应用检查可达性之后但在连接[ 网络概述 ]之前,Wi-Fi信号可能会消失。

  • Different hosts may be reachable over different interfaces. You cannot trust a reachability check for one host to be valid for a different host [Networking Overview].

    通过不同的接口可以访问不同的主机。 您不能相信一台主机对另一台主机有效的可达性检查[ 网络概述 ]

  • Different IP addresses for the same host may be reachable over different interfaces [Networking Overview].

    可以通过不同的接口访问同一主机的不同IP地址[ 网络概述 ]

  • […] You can no longer assume that Internet connectivity, once established, will remain established, or that bandwidth will never increase or decrease […] [Apple’s Networking Overview].

    […]您不能再假定Internet连接一旦建立便会保持建立,或者带宽永远不会增加或减少[…] [ Apple的网络概述 ]

  • Wi-Fi Assist can switch you automatically to cellular if you have a poor Wi-Fi connection so that you can continue using the Internet.

    如果Wi-Fi连接不畅, Wi-Fi Assist可以自动将您切换到蜂窝网络,以便您可以继续使用Internet。

  • Your device might think it’s on Wi-Fi, but when it tries to use it, it turns out not working [Advances in Networking, Part 2, 57:15].

    您的设备可能认为它在Wi-Fi上,但是当它尝试使用Wi-Fi时,它却无法正常工作[ Networkings,Part 2,57:15]

As highlighted in Advances in Networking, instead of disabling app features and letting users hope for the best, we should indicate on the UI that the current connectivity status is insufficient, without blocking any actions. For example, Safari provides a refresh button on a web page which failed to load due to the lack of connectivity since automatic refresh is unreliable:

网络进步中所强调的那样,我们应该在UI上指示当前的连接状态不足,而不阻止任何操作,而不是禁用应用程序功能并让用户期望最好。 例如,Safari提供了一个刷新按钮,该刷新按钮在网页上由于缺乏连接而无法加载,因为自动刷新不可靠:

Image for post

Let’s lay out the idiomatic approach to working with an insufficient Internet connection.

让我们提出一种处理Internet连接不足的惯用方法。

Given that you opted into Adaptable Connectivity, you can now handle connectivity updates via URLSessionDelegate. The following methods are called once per URLSessionTask, and are a good place to indicate the status on the UI, e.g., by presenting an offline mode or a cellular-only mode:

鉴于您选择了Adaptable Connectivity,现在可以通过URLSessionDelegate处理连接更新。 每个URLSessionTask一次调用以下方法,它们是在UI上指示状态的好地方,例如,通过呈现脱机模式或仅蜂窝模式:

class NetworkingHandler: NSObject, URLSessionDelegate {    func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {
// Indicate network status, e.g., offline mode
}

func urlSession(_ session: URLSession, task: URLSessionTask, willBeginDelayedRequest: URLRequest, completionHandler: (URLSession.DelayedRequestDisposition, URLRequest?) -> Void) {
// Indicate network status, e.g., back to online
}
}let session = URLSession(configuration: config, delegate: NetworkingHandler(), delegateQueue: .main)

In case you haven’t opted into Adaptable Connectivity, you should use NWPathMonitor to receive network status updates. First, create a monitor instance. Make sure that you store a strong reference to it, e.g., by having it as a property in AppDelegate:

万一您尚未选择Adaptable Connectivity ,则应使用NWPathMonitor接收网络状态更新。 首先,创建一个监视器实例。 确保存储对它的强引用,例如,通过将其作为AppDelegate的属性来进行:

import Networklet monitor = NWPathMonitor()
monitor.start(queue: .global()) // Deliver updates on the background queue

Then use pathUpdateHandler to handle status changes:

然后使用pathUpdateHandler处理状态更改:

monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
// Indicate network status, e.g., offline mode
} else {
// Indicate network status, e.g., back to online
}
}

The benefits of using NWPathMonitor over SCNetworkReachability is that it offers higher-level APIs, and provides more information about the network connection. We no longer need to create a network socket, and listen for its changes - all using low-level C APIs and pointers.

使用的好处NWPathMonitorSCNetworkReachability的是,它提供了更高级别的API,并提供有关网络连接的更多信息。 我们不再需要创建网络套接字,并监听其更改-全部使用低级C API和指针

Once we receive a network status update — either via URLSessionDelegate or NWPathMonitor - we can diagnose the current connection via NWPathMonitor:

收到网络状态更新(通过URLSessionDelegateNWPathMonitor ,我们可以通过NWPathMonitor诊断当前连接:

if monitor.currentPath.status == .satisfied {
// Connected
} else {
// No connection
}if monitor.currentPath.isExpensive {
// Using an expensive interface, such as Cellular or a Personal Hotspot
}if monitor.currentPath.isConstrained {
// Using Low Data Mode
}

There is still a chance that a connection will drop after it has been established. In such a case, you will receive an NSURLErrorNetworkConnectionLost error in URLSessionTask's completion handler. This is a good place to diagnose connectivity status using NWPathMonitor to handle the error appropriately.

建立连接后仍然有可能断开连接。 在这种情况下,您将在URLSessionTask的完成处理程序中收到NSURLErrorNetworkConnectionLost错误。 这是使用NWPathMonitor正确处理错误来诊断连接状态的好地方。

将约束附加到网络操作 (Attaching Constraints to Network Operations)

Another common scenario is to constrain network operations based on Internet connection status. E.g., disable video autoplay, or automatic downloads, or high quality streaming via cellular.

另一个常见方案是根据Internet连接状态限制网络操作。 例如,禁用视频自动播放,自动下载或通过蜂窝电话的高质量流式传输。

Networking Overview suggests that we should not use Reachability to decide whether a network operation needs to be constrained or not:

网络概述建议我们不要使用可达性来决定是否需要限制网络操作:

Checking the reachability flag does not guarantee that your traffic will never be sent over a cellular connection.

检查可达性标记并不能保证您的流量永远不会通过蜂窝连接发送。

According to Advances in Networking, Part 1, the preferred way of minimizing data usage is by adopting Low Data Mode. Its purpose is to restrict background network use and save cellular and Wi-Fi usage. Since Low Data Mode is a system-wide preference, it gives control into users’ hands. You no longer need to second-guess your users by supporting Low Data Mode in your app.

根据网络进步,第1部分 ,最小化数据使用的首选方法是采用低数据模式 。 其目的是限制后台网络使用并节省蜂窝和Wi-Fi使用。 由于低数据模式是系统范围的首选项,因此可以将控制权交到用户手中。 您不再需要通过在应用程序中支持低数据模式来猜测用户。

We can enable Low Data Mode on a URLSession level:

我们可以在URLSession级别启用低数据模式:

var config = URLSessionConfiguration.default
config.allowsConstrainedNetworkAccess = falselet session = URLSession(configuration: config)let url = URL(string: "https://www.example.com/")!
session.dataTask(with: url) { data, response, error in
// ...
}

Or on a per-request basis:

或根据每个请求:

let url = URL(string: "https://www.example.com/")!var request = URLRequest(url: url)
request.allowsConstrainedNetworkAccess = falseURLSession.shared.dataTask(with: request) { data, response, error in
// ...
}

In this case, when there are no available networks without constraints, HTTP requests will fail with URLError whose networkUnavailableReason is set to .constrained.

在这种情况下,当有没有约束没有可用的网络,HTTP请求将失败,并URLErrornetworkUnavailableReason设置为.constrained

Here are some examples of how built-in iOS apps adapt Low Data Mode [1]:

以下是内置iOS应用如何适应低数据模式[1]的一些示例:

  • App Store: Video autoplay, automatic updates, and automatic downloads are turned off.

    App Store:视频自动播放,自动更新和自动下载已关闭。
  • Music: Automatic downloads and high-quality streaming are turned off.

    音乐:自动下载和高质量流媒体已关闭。
  • Podcasts: The frequency of feed updates is limited, and episodes are downloaded only on Wi-Fi.

    播客:提要更新的频率受到限制,并且仅在Wi-Fi上下载了剧集。
  • News: Article prefetching is turned off.

    新闻:文章预取已关闭。
  • iCloud: Updates are paused, and automatic backups and iCloud Photos updates are turned off.

    iCloud:更新被暂停,并且自动备份和iCloud Photos更新被关闭。
  • FaceTime: Video bitrate is optimized for lower bandwidth.

    FaceTime:视频比特率已针对较低带宽进行了优化。

If Low Data Mode is not what you need, you can use the following properties to make decisions about what to do on a given network:

如果不需要低数据模式,则可以使用以下属性来决定在给定网络上的操作:

  • allowsExpensiveNetworkAccess

    allowsExpensiveNetworkAccess

  • allowsCellularAccess

    allowsCellularAccess

The preferred one is allowsExpensiveNetworkAccess since it is more future-proof than allowsCellularAccess.

首选的方法是allowsExpensiveNetworkAccess因为它比allowsCellularAccess

摘要 (Summary)

Let’s summarize the list of best practices that we’ve discussed:

让我们总结一下我们讨论过的最佳实践:

  • Avoid pre-flight checks. Instead, opt into Adaptable Connectivity APIs.

    避免进行飞行前检查。 相反,请选择Adaptable Connectivity API

  • Do not enable or disable app features based on an Internet connection. Instead, indicate connectivity status on UI, and diagnose network errors.

    不要基于Internet连接启用或禁用应用程序功能。 而是在UI上指示连接状态,并诊断网络错误。
  • Do not use Reachability or NWPathMonitor to prevent connections from being sent over a cellular network. Instead, adapt Low Data Mode.

    不要使用可达性或NWPathMonitor来防止通过蜂窝网络发送连接。 而是改用低数据模式。

翻译自: https://medium.com/@vadimbulavin/working-with-internet-connection-on-ios-with-swift-best-practices-327a4784d10e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值