使用Apple的Reachability检查Swift中的远程服务器可访问性

时间:2014-07-12 13:33:07

标签: ios swift reachability

我正在开发一个用Swift编写的iOS应用程序,它与本地网络上的HTTP服务器通信,我正在使用Apple的Reachability类来确定运行HTTP服务器的远程机器是否在线。这是代码:

...
let RemoteHost: String = "192.168.178.130"
var RemoteReachability: Reachability! = nil
var RemoteIsReachable: Bool = false

init() {
        super.init()
        self.RemoteReachability = Reachability(hostName: self.RemoteHost)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: kReachabilityChangedNotification, object: self.RemoteReachability)
        self.RemoteReachability.startNotifier()
        self.RemoteIsReachable = (self.RemoteReachability.currentReachabilityStatus().value == ReachableViaWiFi.value)
}

func reachabilityChanged(notification: NSNotification) {
    let ReachabilityInst: Reachability = notification.object as Reachability
    self.RemoteIsReachable = (ReachabilityInst.currentReachabilityStatus().value == ReachableViaWiFi.value)
}

问题是无论远程机器是在线还是离线,

(ReachabilityInst.currentReachabilityStatus().value == ReachableViaWiFi.value)

只要我连接到Wifi网络,总是如此。但是,当我关闭Wifi时,它会导致错误而不是真实。我在这里做错了什么,或者Reachability类是否与Swift / xCode 6 Beta不兼容?我也试过这个:

(ReachabilityInst.currentReachabilityStatus() == ReachableViaWiFi)

但是这导致xCode告诉我“无法找到接受提供的参数的'=='的重载”,即使两者看起来都是'NetworkStatus'类型。

提前致谢。

4 个答案:

答案 0 :(得分:32)

您正在使用的Reachability类是基于Apple的SCNetworkReachability类,它并不完全符合您的希望。来自SCNetworkReachability documentation

  

当数据包发送时,远程主机被认为是可达的   应用程序进入网络堆栈,可以离开本地设备。   可达性不保证数据包实际上是   收到主持人的回复。

因此,它不是用于测试远程主机是否实际在线,只是(1)当前网络设置是否允许尝试到达它和(2)通过什么方法。一旦确定网络处于活动状态,您就需要尝试连接以查看远程主机是否实际启动并运行。


注意:此测试:

(ReachabilityInst.currentReachabilityStatus().value == ReachableViaWiFi.value)

是检查的正确方法 - 由于某种原因NetworkStatus是为数不多的Apple enumerations created without the NS_ENUM macro之一。

答案 1 :(得分:11)

在swift中,

关于我对 Apple https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html)或 tonymillion https://github.com/tonymillion/Reachability)提出的可达性效用的理解 基本相同的是:

你有3个可能的测试:

  • 本地 (可以访问本地网络,但不能访问互联网)
  • extern (可通过IP地址访问互联网)
  • dns (可以访问互联网并获取主机名)

您可以通过以下方式启动通知程序来分别测试它们:

let wifiReachability = Reachability. reachabilityForLocalWiFi()
wifiReachability.startNotifier()

let internetReachability = Reachability.reachabilityForInternetConnection()
hostReachability.startNotifier()

let hostReachability = Reachability(hostName:"www.apple.com")
hostReachability.startNotifier()

这将触发您可以使用此方法捕获的通知: NSNotificationCenter.defaultCenter()。addObserver()

所以要使用它们你可以做类似的事情:

在你的appDelegate中创建一个函数,它将实例化通知程序:

func startReachabilityTest()
{
    // Allocate a reachability object to test internet access by hostname
    let reach = Reachability(hostName: "www.apple.com")

    // Tell the reachability that we DON'T want to be reachable on 3G/EDGE/CDMA
    //reach.reachableOnWWAN = false

    reach.startNotifier()
}

然后你可以在appDelegate的didFinishLaunchingWithOptions中调用它:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    self.startReachabilityTest();
}

如果想在任何viewController中捕获事件,只需将此行添加到viewDidLoad:

override func viewDidLoad()
{
    // Here we set up a NSNotification observer. The Reachability that caused the notification
    // is passed in the object parameter
    NSNotificationCenter.defaultCenter().addObserver(
            self,
            selector: "reachabilityChanged:",
            name: kReachabilityChangedNotification,
            object: nil)
}

并添加此方法方法以对事件做出反应:

func reachabilityChanged(notice: NSNotification)
{
    println("reachability changed")
    let reach = notice.object as? Reachability
    if let remoteHostStatus = reach?.currentReachabilityStatus()
    {
        if remoteHostStatus == NetworkStatus.NotReachable
        {
            println("not reachable")
        }
        else
        {
            println("reachable")
        }
    }
}

您还可以通过在didFinishLaunchingWithOptions中添加 NSNotificationCenter.defaultCenter()。addObserver()来在appDelegate中捕获事件,然后在其中添加 reachabilityChanged(注意:NSNotification)

啊,还要注意,通过添加以下行,您可以使用cocoapods轻松地将可达性类添加到项目中:

pod 'Reachability', '~> 3.2'

在命令行中 pod install 之后,将您的pod文件添加到 xxx-Bridging-Header.h 头文件中(其中xxx是名称)你的应用程序):

#import <Reachability/Reachability.h>

如果您的项目中没有桥接标题,则可以按照本教程进行操作:http://www.learnswiftonline.com/getting-started/adding-swift-bridging-header/

无需添加已由pod依赖项添加的systemConfiguration.framework。

注意:可达性在模拟器中不能正常工作

希望这有帮助!

答案 2 :(得分:2)

如果您正在寻找Swift实施Apple的Reachability类,您可以看一下:

http://github.com/ashleymills/Reachability.swift

使用通知和闭包,这是课堂上的一个下降。

适用于iOS和OS X,并支持Cocoapod / Carthage。

祝你好运!

答案 3 :(得分:0)

使用组合和可达性:

import Combine
import Reachability
import os

class ReachabilityStore: ObservableObject {
    private var reachability: Reachability

    @Published var reachable: Bool = false
    @Published var reachableViaWifi: Bool = false
    @Published var reachableViaCellular: Bool = false

    init() {
        reachability = try! Reachability()

        reachability.whenReachable = { [weak self] reachability in
            guard let self = self else { return }

            self.reachable = true
            self.reachableViaWifi = reachability.connection == .wifi
            self.reachableViaCellular = !self.reachableViaWifi

            os_log(
                "Reachable via %{public}s",
                self.reachableViaWifi ? "WiFi" : "Cellular"
            )
        }

        reachability.whenUnreachable = { [weak self] _ in
            guard let self = self else { return }

            os_log("Unreachable")

            self.reachable = false
            self.reachableViaWifi = false
            self.reachableViaCellular = false
        }

        do {
            try reachability.startNotifier()
        } catch {
            os_log("Unable to start reachability notifier.")
        }
    }
}