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

Я разрабатываю приложение iOS, написанное в Swift, которое общается с 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)

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

(ReachabilityInst.currentReachabilityStatus() == ReachableViaWiFi)

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

Спасибо заранее.

Ответ 1

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

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

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


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

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

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

Ответ 2

В быстром,

О том, что я понял о полезности достижимости, предлагаю 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 install в командной строке просто добавьте эту строку в заголовок xxx-Bridging-Header.h (где xxx - это имя вашего приложения):

#import <Reachability/Reachability.h>

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

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

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

надеюсь, что эта помощь!

Ответ 3

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

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

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

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

Удачи!