Reachability.swift
在需要获取手机网络连接方式的时候,Reachability库是一个很好的工具。它可以判断当前网络状态是
- Wi-Fi(wifi)
- 蜂窝移动(cellular)
- 没有连接(none和unavailable,据说在之后的版本中会取消none)
并且在github的不断更新中,现在的Reachability.swift已经支持了swift5.0,并且可以通过swift package manager导入项目中。
官方给的文档中使用方式已经介绍的很清晰了,同时也可以自己稍加改变结合swiftUI或Combine使用。官方给的代码是:
- 在闭包中使用:
let reachability = try! Reachability()
reachability.whenReachable = { reachability in
if reachability.connection == .wifi {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
}
reachability.whenUnreachable = { _ in
print("Not reachable")
}
do {
try reachability.startNotifier()
} catch {
print("Unable to start notifier")
}
- 在自定义类或结构体中使用(主队列):
let reachability = try! Reachability()
//添加观察者的语句,可以封装在方法中
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(note:)), name: .reachabilityChanged, object: reachability)
do{
try reachability.startNotifier()
}catch{
print("could not start reachability notifier")
}
//发布通知的代码,广播
@objc func reachabilityChanged(note: Notification) {
let reachability = note.object as! Reachability
switch reachability.connection {
case .wifi:
print("Reachable via WiFi")
case .cellular:
print("Reachable via Cellular")
case .unavailable:
print("Network not reachable")
}
}
//移除观察者的语句,同时停止发布通知
reachability.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability)
wifi SSID
在使用时,与获取网络状态相关的功能就是读取Wi-Fi状态下的Wi-Fi信息。SSID(service set identifier)服务集标识符,一般可以当作局域网的名称。同样在github上有一个项目是可以实现获取Wi-Fi info的,对于iOS13及以下都支持。下面截取一个常用的方法:
import Foundation
import SystemConfiguration.CaptiveNetwork
func getSSID() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
//这里的 as! 强制类型转换是可以成功的
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
}
注意
在使用时也需要根据项目的要求对上面的信息做一些改变,比如let reachability = try! Reachability()
这个初始化语句,使用了强制try
,应谨慎表达式抛出错误,引发运行时错误。我的方法是:
- 改为
try?
忽略错误,同时在后面reachability的调用中使用可选链 - 改为
try
,使用do-catch
语句包围。
特别是如果使用了Future
这样的publisher,就要格外注意初始化的成败。如果初始化失败future不会发出任何消息,但是在项目的程序调用中一般是认为future是会发出消息的,这样可能会在之后的调用中产生问题。所以要在初始化时就增加判断机制,失败时抛错并return。
此外在写工程代码时要注意避免“不优雅”的多层嵌套。衡量代码好坏的一个重要标准是代码的“深度”,即嵌套层数。多层嵌套降低代码的可读性,同时也会消耗内存资源。因为执行程序其实就是内存的入栈出栈,过分嵌套可能导致爆栈(可以理解为俄罗斯套娃,套得越深取出来的步骤就越复杂,也更耗时)。
以上,在写完代码后要二次检查:
- 功能能否正常实现
- 常变量、方法的命名是否规范
- 代码的判断机制和错误处理机制是否合乎逻辑,不累赘丑陋
- 注释是否规范,特别是对复杂语句要有必要的注释(比如
try!
as!
的使用要写明白为什么会确保不出问题)
完成以上内容之后,根据工作的性质按照commit规范
提交。
乌拉!
2020.2.26更新记录一下
在使用combine的时候没有注意引用持有,reachability在调用完成之后就被销毁了,使用Future发布不了任何值。最可怕的是我找bug找了一下午也没看出来是引用持有发生了问题(真菜啊),所以还要复习一下属性的生命周期。之前学的时候没有实际体会,现在有了实际体会又不会用了(逃
重要的是功能代码一定要自己测试测试测试!重要的事情说三遍!debug preview的模式就可以
2.27记录
whenReachable 和 whenUnreachable这两个闭包使用的时候要注意,他们是在网络状态发生改变的时候才会发出值的,在使用combine结合项目的时候最好看一起reachability的源码,获取网络的状态可以直接通过实例化Reachability之后访问connnection属性拿到。