Использование доступности Apple для проверки доступности удаленного сервера в Swift


Я разрабатываю приложение iOS, написанное на Swift, которое взаимодействует с HTTP-сервером в локальной сети, и я использую класс достижимости Apple, чтобы определить, находится ли удаленная машина, на которой работает 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)

Всегда верно, пока я подключен к сети Wi-Fi. Однако, когда я выключить WiFi, оно влечет за собой ложные вместо истинный. Я делаю что-то не так, или класс достижимости просто еще не совместим с бета-версией Swift / xCode 6? Я также попробовал это:

(ReachabilityInst.currentReachabilityStatus() == ReachableViaWiFi)

Но это приводит к тому, что xCode говорит мне: "не удалось найти перегрузку для'==', которая принимает предоставленные аргументы", хотя оба они, по-видимому, относятся к типу 'NetworkStatus'.

Заранее благодарю.

3 16

3 ответа:

Класс достижимости, который вы используете, основан на классе SCNetworkReachability от Apple, который не делает именно то, на что вы надеетесь. Из документации SCNetworkReachability :

Удаленный хост считается доступным, когда пакет данных, отправленный приложение в сетевой стек, может покинуть локальное устройство. Достижимость не гарантирует, что пакет данных действительно будет принят хозяином.

Таким образом, он не создан для тестирования того, или нет, удаленный хост на самом деле находится в сети, только ли (1) текущие сетевые настройки позволят попытаться достичь его и (2) какими методами. После того, как вы определили, что сеть активна, вам нужно будет попытаться подключиться, чтобы увидеть, действительно ли удаленный хост работает.


Примечание: этот тест:

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

Является правильным способом проверки -- по какой-то причине NetworkStatus является одним из немногих перечислений Apple , созданных без NS_ENUM макрос .

В 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()
}

Тогда вы можете вызвать его в didFinishLaunchingWithOptions вашего appDelegate:

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")
        }
    }
}

Вы также можете перехватить событие внутри вашего appDelegate, добавив NSNotificationCenter.defaultCenter ().addObserver () внутри didFinishLaunchingWithOptions и затем добавить reachabilityChanged (Примечание: NSNotification) В нем.

Ах, также обратите внимание, что вы можете легко добавить класс достижимости в свой проект с cocoapods, добавив эту строку:

pod 'Reachability', '~> 3.2'

В ваш pod-файл и их после установки pod в командной строке просто добавьте эту строку в xxx-Bridging-Header.H заголовочный файл (где xxx-имя вашего приложения):

#import <Reachability/Reachability.h>

Если у вас нет заголовка bridging в вашем проекте, вы можете следовать этому руководству : http://www.learnswiftonline.com/getting-started/adding-swift-bridging-header/

Нет необходимости добавлять systemConfiguration.фреймворк, который уже добавлен зависимостями pod.

Примечание: достижимость не работает нормально в симуляторе

Надеюсь на эту помощь!

Если вы ищете быструю реализацию класса достижимости Apple, вы можете взглянуть на это:

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

Это падение класса, используя уведомления и закрытие.

Он работает с iOS и OS X и имеет поддержку Cocoapod / Carthage.

Удачи!