当我试着在我的iPhone上检查网络连接时,我得到了一堆错误。有人能帮我解决这个问题吗?
代码:
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}
var flags: SCNetworkReachabilityFlags = 0
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
return false
}
let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection) ? true : false
}
}
代码的错误:
如果它是不可读的,错误1说:
'Int'不能转换为'SCNetworkReachabilityFlags'
错误2和3:
找不到一个超载的'init'接受提供的参数
如果你的项目有一个高于或等于iOS 12的目标,并使用组合,你可以使用这一小段代码。
import Combine
import Network
enum NerworkType {
case wifi
case cellular
case loopBack
case wired
case other
}
protocol ReachabilityServiceContract {
var reachabilityInfos: PassthroughSubject<NWPath, Never> { get set }
var isNetworkAvailable: CurrentValueSubject<Bool, Never> { get set }
var typeOfCurrentConnection: PassthroughSubject<NerworkType, Never> { get set }
}
final class ReachabilityService: ReachabilityServiceContract {
var reachabilityInfos: PassthroughSubject<NWPath, Never> = .init()
var isNetworkAvailable: CurrentValueSubject<Bool, Never> = .init(false)
var typeOfCurrentConnection: PassthroughSubject<NerworkType, Never> = .init()
private let monitor: NWPathMonitor
private let backgroudQueue = DispatchQueue.global(qos: .background)
init() {
monitor = NWPathMonitor()
setUp()
}
init(with interFaceType: NWInterface.InterfaceType) {
monitor = NWPathMonitor(requiredInterfaceType: interFaceType)
setUp()
}
deinit {
monitor.cancel()
}
}
private extension ReachabilityService {
func setUp() {
monitor.pathUpdateHandler = { [weak self] path in
self?.reachabilityInfos.send(path)
switch path.status {
case .satisfied:
self?.isNetworkAvailable.send(true)
case .unsatisfied, .requiresConnection:
self?.isNetworkAvailable.send(false)
@unknown default:
self?.isNetworkAvailable.send(false)
}
if path.usesInterfaceType(.wifi) {
self?.typeOfCurrentConnection.send(.wifi)
} else if path.usesInterfaceType(.cellular) {
self?.typeOfCurrentConnection.send(.cellular)
} else if path.usesInterfaceType(.loopback) {
self?.typeOfCurrentConnection.send(.loopBack)
} else if path.usesInterfaceType(.wiredEthernet) {
self?.typeOfCurrentConnection.send(.wired)
} else if path.usesInterfaceType(.other) {
self?.typeOfCurrentConnection.send(.other)
}
}
monitor.start(queue: backgroudQueue)
}
}
只要订阅你想要跟踪的变量,你就会得到任何变化的更新。
我使用NSTimer和Alamofire制作了自己的解决方案:
import Alamofire
public class ConnectionHelper: NSObject {
var request: Alamofire.Request?
func isInternetConnected(completionHandler: Bool -> Void) {
NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "requestTimeout", userInfo: nil, repeats: false)
request = Alamofire
.request(
Method.HEAD,
"http://www.testurl.com"
)
.response { response in
if response.3?.code == -999 {
completionHandler(
false
)
} else {
completionHandler(
true
)
}
}
}
func requestTimeout() {
request!.cancel()
}
}
NSTimer被用作超时,并且由于使用Alamofire超时的不可靠结果而被使用。请求应该发送到您认为可靠的URL,例如您自己的服务器或托管您所依赖的服务的服务器。
当计时器过期时,请求将被取消,并使用完成处理程序返回结果。
用法:
ConnectionHelper().isInternetConnected() { internetConnected in
if internetConnected {
// Connected
} else {
// Not connected
}
}
这是我的版本。本质上,它没有带来任何新东西。我把它绑定到UIDevice。
import UIKit
import SystemConfiguration
extension UIDevice {
open class var isConnectedToNetwork: Bool {
get {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard
let defaultRouteReachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}),
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags() as SCNetworkReachabilityFlags?,
SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
else { return false }
return flags.contains(.reachable) && !flags.contains(.connectionRequired)
}
}
}
print("Network status availability: " + ( UIDevice.isConnectedToNetwork ? "true" : "false" ))
iOS12 Swift 4和Swift 5
如果你只是想检查连接,你的最低目标是iOS12,那么你可以使用NWPathMonitor
import Network
它需要一些属性的设置。
let internetMonitor = NWPathMonitor()
let internetQueue = DispatchQueue(label: "InternetMonitor")
private var hasConnectionPath = false
我创建了一个函数来启动它。你可以在viewdidload或其他地方做这个。我派了个保镖,你想怎么打就怎么打。
func startInternetTracking() {
// only fires once
guard internetMonitor.pathUpdateHandler == nil else {
return
}
internetMonitor.pathUpdateHandler = { update in
if update.status == .satisfied {
print("Internet connection on.")
self.hasConnectionPath = true
} else {
print("no internet connection.")
self.hasConnectionPath = false
}
}
internetMonitor.start(queue: internetQueue)
}
/// will tell you if the device has an Internet connection
/// - Returns: true if there is some kind of connection
func hasInternet() -> Bool {
return hasConnectionPath
}
现在只需调用helper函数hasInternet()来查看是否有。它实时更新。请参阅Apple文档中的NWPathMonitor。它有更多的功能,如取消(),如果你需要停止跟踪连接,你正在寻找的互联网类型等。
https://developer.apple.com/documentation/network/nwpathmonitor
对于Swift 3, Swift 4(使用蜂窝和Wi-Fi):
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
return false
}
/* Only Working for WIFI
let isReachable = flags == .reachable
let needsConnection = flags == .connectionRequired
return isReachable && !needsConnection
*/
// Working for Cellular and WIFI
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
let ret = (isReachable && !needsConnection)
return ret
}
}
用法:
if Reachability.isConnectedToNetwork(){
print("Internet Connection Available!")
}else{
print("Internet Connection not Available!")
}