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


当前回答

虽然它可能不能直接确定手机是否连接到网络,但最简单的解决方案是“ping”谷歌或其他服务器(除非手机连接到网络,否则这是不可能的):

private var urlSession:URLSession = {
    var newConfiguration:URLSessionConfiguration = .default
    newConfiguration.waitsForConnectivity = false
    newConfiguration.allowsCellularAccess = true
    return URLSession(configuration: newConfiguration)
}()

public func canReachGoogle() -> Bool
{
    let url = URL(string: "https://8.8.8.8")
    let semaphore = DispatchSemaphore(value: 0)
    var success = false
    let task = urlSession.dataTask(with: url!)
    { data, response, error in
        if error != nil
        {
            success = false
        }
        else
        {
            success = true
        }
        semaphore.signal()
    }

    task.resume()
    semaphore.wait()

    return success
}

如果您担心服务器可能宕机或阻塞您的IP,您总是可以以类似的方式ping多个服务器,并返回它们中的任何一个是否可达。或者让别人专门为这个目的设置一个专用服务器。

其他回答

在项目中创建一个新的Swift文件,命名为Reachability.swift。将以下代码剪切并粘贴到其中以创建您的类。

import Foundation
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(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
            SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0))
        }

        var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
             return false
        }

        let isReachable = flags == .Reachable
        let needsConnection = flags == .ConnectionRequired

        return isReachable && !needsConnection

    }
}

你可以使用下面的代码检查项目中的任何地方的互联网连接:

if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
}

如果用户没有连接到互联网,您可能希望向他们显示一个警告对话框来通知他们。

if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
    var alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
    alert.show()
}

解释:

我们正在制作一个可重用的公共类和方法,可以在项目的任何地方使用,以检查互联网连接。我们需要添加基础和系统配置框架。

在公共类Reachability中,方法isConnectedToNetwork() -> Bool{}将返回一个关于互联网连接的Bool值。我们使用if循环对case执行所需的操作。我希望这足够了。干杯!

Xcode 14.0, Swift 5.7

要检查互联网连接,请使用苹果的本地网络框架。它有NWPathMonitor类观察者,你可以实现它来监视和响应网络变化。

import Network

class ViewController: UIViewController {       
    @IBOutlet var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.networkMonitoring()
    }
    
    fileprivate func networkMonitoring() {
        let monitor = NWPathMonitor()
        let queue = DispatchQueue(label: "monitoring")
        monitor.start(queue: queue)
        
        monitor.pathUpdateHandler = { path in
            DispatchQueue.main.async {
                switch path.status {
                    case .satisfied:
                        self.label.text = "Intenet connected"
                        self.view.backgroundColor = .systemGreen
                    case .unsatisfied:
                        self.label.text = "No Intenet"
                        self.view.backgroundColor = .systemRed
                    case .requiresConnection:
                        self.label.text = "May be activated"
                        self.view.backgroundColor = .systemBlue
                    @unknown default:  fatalError()
                }
            }
        }
    }
}

如果你的项目有一个高于或等于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)
    }
}

只要订阅你想要跟踪的变量,你就会得到任何变化的更新。

在项目中创建一个新的Swift文件,命名为Reachability.swift。将以下代码剪切并粘贴到其中以创建您的类。

import Foundation
import SystemConfiguration

open class Reachability {
    
    class func isConnectedToNetwork() -> Bool {
        
        var zeroAddress = sockaddr_in()
        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()
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
            return false
        }
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        return (isReachable && !needsConnection)
    }
}

你可以在代码的任何地方调用Reachability,就像

if Reachability.isConnectedToNetwork() {
    print("Network is connected")
} else {
    print("Network is not connected")
}

这是与接受的答案相同的代码,但我发现在某些情况下使用闭包更有用

import SystemConfiguration

public class Reachability {

    class func isConnectedToNetwork(isConnected : (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 {
            isConnected(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)

        isConnected(ret)
    }
}

下面是如何使用它:

Reachability.isConnectedToNetwork { (isConnected) in
    if isConnected {
        //We have internet connection | get data from server
    } else {
        //We don't have internet connection | load from database 
    }
}