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


当前回答

虽然没有直接回答你的问题,但我想提一下苹果公司最近有这样一个谈话:

https://developer.apple.com/videos/play/wwdc2018/714/

大约在9点55分,他谈到了做你正在问的事情:

检查连接 如果连接->做点什么 如果没有连接->执行其他操作(等待?重试?)

然而,这有一些陷阱:

如果在第二步中,它说它有连接,但0.5秒后他就没有了呢? 如果用户在代理的后面呢 最后但并非最不重要的是,如果这里的一些答案不能确定连通性呢?(我敢肯定,如果你快速切换你的连接,去wi-fi,然后关掉它(只是让它变得复杂),它几乎永远不能正确地判断我是否获得了连接)。 视频中说:“没有办法保证未来的行动是否会成功。”

以下是苹果公司的一些最佳实践:

设置waitsForConnectivity为true (https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity) 响应委托方法taskIsWaitingForConnectivity (https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/2908819-urlsession)。这是苹果推荐的检查连接的方法,正如33:25的视频中提到的那样。

根据谈话,不应该有任何理由预先检查你是否有互联网连接,因为在你向服务器发送请求时,它可能并不准确。

其他回答

苹果在iOS12中引入了网络框架。

import Foundation
import Network

class NetworkReachability {

    var pathMonitor: NWPathMonitor!
    var path: NWPath?
    lazy var pathUpdateHandler: ((NWPath) -> Void) = { path in
        self.path = path
        if path.status == NWPath.Status.satisfied {
            print("Connected")
        } else if path.status == NWPath.Status.unsatisfied {
            print("unsatisfied")
        } else if path.status == NWPath.Status.requiresConnection {
            print("requiresConnection")
        }
    }

    let backgroudQueue = DispatchQueue.global(qos: .background)

    init() {
        pathMonitor = NWPathMonitor()
        pathMonitor.pathUpdateHandler = self.pathUpdateHandler
        pathMonitor.start(queue: backgroudQueue)
    }

    func isNetworkAvailable() -> Bool {
        if let path = self.path {
            if path.status == NWPath.Status.satisfied {
                return true
            }
        }
        return false
    }
}

Swift 5解决方案:

下载ashleymills的Reachability类 https://github.com/ashleymills/Reachability.swift。 将Reachability类添加到项目中。 将以下代码放入维护连接状态的类中

class ConnectionManager {

    static let shared = ConnectionManager()
    private init () {}

    func hasConnectivity() -> Bool {
        do {
            let reachability: Reachability = try Reachability()
            let networkStatus = reachability.connection
            
            switch networkStatus {
            case .unavailable:
                return false
            case .wifi, .cellular:
                return true
            }
        }
        catch {
            return false
        }
    }
}

像下面这样使用它:

ConnectionManager.shared.hasConnectivity()

虽然它可能不能直接确定手机是否连接到网络,但最简单的解决方案是“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多个服务器,并返回它们中的任何一个是否可达。或者让别人专门为这个目的设置一个专用服务器。

斯威夫特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
}

There is no real way to do this, even APIs that do this will try to connect to a particular service and tell you if it succeed after previously failing, the best approach is to just try to connect to your service and handle the error appropriately, if you want some service that will notify you when you become connected, all that will happens is that it periodically calls to a fixed service until it gets a response and then let you know that it succeed, what if the problem is not the internet itself but the specific service you are trying to connect to.

最好的方法是在你的连接方法中设计处理这个问题的方法,你可以在给定的时间内触发重试,这取决于你的错误,也许是失败的数量,你可以返回一个错误,你可以用它来显示一个错误消息,给用户一个重试的可能性,也许是尝试几次,然后返回和错误的组合。

另一个类似的问题是发送你已经发送但还没有得到响应的消息,最好还是写你的应用程序来处理这个,忽略请求,直到它等待的请求返回,如果请求不同,取消等待请求,等等

这些东西可以以非常通用的方式编写,所以它们可以用于应用程序的许多不同方面,甚至不同的项目。