当我试着在我的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'接受提供的参数


当前回答

在以下代码的帮助下,您可以检查网络连接的蜂窝网络以及wifi。 Swift 3.0

import UIKit
import Foundation
import SystemConfiguration

class NetworkConnection: UIViewController {

  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)

    guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
      $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        SCNetworkReachabilityCreateWithAddress(nil, $0)
      }
    }) else {
      return false
    }

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
      return false
    }
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
  }

  class func checkConnection(sender:UIViewController){
    if NetworkConnection.isConnectedToNetwork() == true {
      print("Connected to the internet")
      //  Do something
    } else {
      print("No internet connection")
      let alertController = UIAlertController(title: "No Internet Available", message: "", preferredStyle: UIAlertControllerStyle.alert)
      let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){(result:UIAlertAction) -> Void in
        return
      }
      alertController.addAction(okAction)
      sender.present(alertController, animated: true, completion: nil)
      //  Do something
    }
  }

}

其他回答

如果你正在使用Alamofire,你可以这样做:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15 //Set timeouts in sec
configuration.timeoutIntervalForResource = 15

let alamoFireManager = Alamofire.Manager(configuration:configuration)
alamoFireManager?.request(.GET, "https://yourURL.com", parameters: headers, encoding: .URL)
                     .validate()
                              .responseJSON { response in

                                if let error = response.result.error {
                                   switch error.code{
                                    case -1001:
                                        print("Slow connection")
                                        return
                                    case -1009:
                                        print("No Connection!")
                                        return
                                    default: break
                                    }
                                }

斯威夫特5

import SystemConfiguration    

protocol Utilities {}
extension NSObject: Utilities {
    enum ReachabilityStatus {
        case notReachable
        case reachableViaWWAN
        case reachableViaWiFi
    }
    
    var currentReachabilityStatus: ReachabilityStatus {
        
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return .notReachable
        }
        
        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return .notReachable
        }
        
        if flags.contains(.reachable) == false {
            // The target host is not reachable.
            return .notReachable
        }
        else if flags.contains(.isWWAN) == true {
            // WWAN connections are OK if the calling application is using the CFNetwork APIs.
            return .reachableViaWWAN
        }
        else if flags.contains(.connectionRequired) == false {
            // If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
            return .reachableViaWiFi
        }
        else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
            // The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
            return .reachableViaWiFi
        }
        else {
            return .notReachable
        }
    }
}

在任何方法中使用下面的条件

if currentReachabilityStatus == .notReachable {
    // Network Unavailable
} else {
    // Network Available
}

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

我使用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
    }
}

我改进了莱科斯的例子。我添加了一些额外的控件来解决双重触发问题,还添加了通知支持来侦听状态更改。

我为防止双重触发问题而添加的控件还显示了设备主要使用哪个连接源来访问互联网。

例如,即使设备同时连接到蜂窝网络和Wi-Fi,“状态”返回为“connectedViaWiFi”,以指示当前的互联网访问是通过Wi-Fi。

import Foundation
import Network

class Reachability {

    enum StatusFlag {
        case unknow
        case noConnection
        case connectedViaWiFi
        case connectedViaCellular
    }

    static let connectionStatusHasChangedNotification = NSNotification.Name("Reachability.connectionStatusHasChangedNotification")
    static let shared = Reachability()

    private var monitorForWifi: NWPathMonitor?
    private var monitorForCellular: NWPathMonitor?
    private var wifiStatus: NWPath.Status = .requiresConnection
    private var cellularStatus: NWPath.Status = .requiresConnection
    private var ignoreInitialWiFiStatusUpdate: Bool = true
    private var ignoreInitialCelluluarStatusUpdate: Bool = true
    private var isReachableOnCellular: Bool { cellularStatus == .satisfied }
    private var isReachableOnWiFi: Bool { wifiStatus == .satisfied }
    var status: StatusFlag = .unknow {
        didSet {
            guard status != oldValue else { return }
            DispatchQueue.main.async { [weak self] in
                NotificationCenter.default.post(name: Self.connectionStatusHasChangedNotification,
                                                object: self?.status)
            }
        }
    }

    func startMonitoring() {
        monitorForWifi = NWPathMonitor(requiredInterfaceType: .wifi)
        monitorForWifi?.pathUpdateHandler = { [weak self] path in
            self?.wifiStatus = path.status
            self?.ignoreInitialWiFiStatusUpdate = false
            self?.updateStatus()
        }
        monitorForCellular = NWPathMonitor(requiredInterfaceType: .cellular)
        monitorForCellular?.pathUpdateHandler = { [weak self] path in
            self?.cellularStatus = path.status
            self?.ignoreInitialCelluluarStatusUpdate = false
            self?.updateStatus()
        }
        let queue = DispatchQueue.global(qos: .background)
        monitorForCellular?.start(queue: queue)
        monitorForWifi?.start(queue: queue)
    }

    func stopMonitoring() {
        monitorForWifi?.cancel()
        monitorForWifi = nil
        monitorForCellular?.cancel()
        monitorForCellular = nil
        wifiStatus = .requiresConnection
        cellularStatus = .requiresConnection
        status = .unknow
        ignoreInitialWiFiStatusUpdate = true
        ignoreInitialCelluluarStatusUpdate = true
    }

    private func updateStatus() {
        if ignoreInitialWiFiStatusUpdate || ignoreInitialCelluluarStatusUpdate {
            return
        }
        if !(isReachableOnCellular && isReachableOnWiFi) {
            if isReachableOnCellular && !isReachableOnWiFi {
                status = .connectedViaCellular
            } else if isReachableOnWiFi && !isReachableOnCellular {
                status = .connectedViaWiFi
            } else {
                status = .noConnection
            }
        } else {
            status = .connectedViaWiFi
        }
    }

    static func isConnectedToNetwork() -> Bool {
        return shared.isReachableOnCellular || shared.isReachableOnWiFi
    }
}

示例使用

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(_:)), name: Reachability.connectionStatusHasChangedNotification, object: nil)
        Reachability.shared.startMonitoring()
    }

    @objc func reachabilityChanged(_ sender: Notification) {
        guard let statusFlag = sender.object as? Reachability.StatusFlag else { return }
        print("TEST -> statusFlag: \(statusFlag)")
    }