web-dev-qa-db-ja.com

Appleの到達可能性を使用して、リモートサーバーの到達可能性をSwift

ローカルネットワーク上のHTTPサーバーと通信するSwiftで記述されたiOSアプリケーションを開発しています。また、HTTPサーバーを実行しているリモートマシンがオンラインかどうかを判断するためにAppleのReachabilityクラスを使用しています。コードは次のとおりです。

...
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をオフにすると、trueではなくfalseになります。私はここで何か間違っているのですか、それともReachabilityクラスはまだSwift/xCode 6 Betaと互換性がないのですか?私もこれを試しました:

(ReachabilityInst.currentReachabilityStatus() == ReachableViaWiFi)

しかし、その結果、xCodeは「指定された引数を受け入れる '=='のオーバーロードを見つけることができませんでした」と通知しますが、どちらも 'NetworkStatus'タイプであるように見えます。

前もって感謝します。

17
v8_bigblock

使用しているReachabilityクラスは、AppleのSCNetworkReachabilityクラスに基づいています。これは、期待どおりの動作をしません。 SCNetworkReachabilityドキュメント から:

アプリケーションからネットワークスタックに送信されたデータパケットがローカルデバイスを離れることができる場合、リモートホストは到達可能と見なされます。到達可能性は、データパケットが実際にホストによって受信されることを保証するものではありません。

したがって、リモートホストが実際にオンラインであるかどうかをテストするために構築されているのではなく、(1)現在のネットワーク設定がそれに到達する試みを許可するかどうか、および(2)どの方法でアクセスできるかだけです。ネットワークがアクティブであると判断したら、リモートホストが実際に稼働しているかどうかを確認するために接続を試行する必要があります。


注:このテスト:

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

は正しいチェック方法です-何らかの理由でNetworkStatusはいくつかのApple NS_ENUMマクロなしで作成された列挙) の1つです。

33
Nate Cook

スウィフトでは、

Applehttps://developer.Apple.com/library/ios/samplecode/Reachability)が提案する到達可能性ユーティリティについて理解したことについて/Introduction/Intro.html )またはtonymillionhttps://github.com/tonymillion/Reachability )基本的に同じです:

あなたは3つの可能なテストがあります:

  • local(ローカルネットワークにはアクセスできますが、インターネットにはアクセスできません)
  • 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)
}

イベントに反応するこのメソッドmethodを追加します:

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(notice: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/

ポッドの依存関係によってすでに追加されているsystemConfiguration.frameworkを追加する必要はありません。

注:到達可能性はシミュレーターでは正常に機能しません

この助けを願っています!

12
Dragouf

Appleの到達可能性クラスのSwift実装)を探しているなら、これを見てみることができます:

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

これはクラスのドロップであり、通知とクロージャを使用しています。

IOSおよびOS Xで動作し、Cocoapod/Carthageをサポートしています。

幸運を!

2
Ashley Mills

結合と到達可能性の使用:

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.")
        }
    }
}
0
Mycroft Canner