【IOS】建立易於使用的擴充套件程式/功能以實現可達性(主機/網際網路WIFI,蜂窩網路)

2020-11-05 IOS

我正在開發一個複雜的應用程式,我想在從伺服器接收資料的每個ViewController上測試兩個主機的網際網路可訪問性,我目前正在使用此庫來實現可訪問性

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

我想建立一個簡單的方法或擴充套件,以檢查網際網路和主機的可達性
我已經在下面的庫中使用了示例程式碼:`import UIKit

import Reachability

class VC22: UIViewController {

@IBOutlet weak var networkStatus: UILabel!
@IBOutlet weak var hostNameLabel: UILabel!

var reachability: Reachability?

override func viewDidLoad() {
    super.viewDidLoad()

    // Start reachability without a hostname intially
    setupReachability(nil, useClosures: true)
    startNotifier()

    // After 5 seconds, stop and re-start reachability, this time using a hostname
    let dispatchTime = DispatchTime.now() + DispatchTimeInterval.seconds(5)
    DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
        self.stopNotifier()
        self.setupReachability("http://81.28.42.42:4242/", useClosures: true)
        self.startNotifier()

        let dispatchTime = DispatchTime.now() + DispatchTimeInterval.seconds(5)
        DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
            self.stopNotifier()
            self.setupReachability("invalidhost", useClosures: true)
            self.startNotifier()            }

    }
}

func setupReachability(_ hostName: String?, useClosures: Bool) {
    hostNameLabel.text = hostName != nil ? hostName : "No host name"

    print("--- set up with host name: \(hostNameLabel.text!)")

    let reachability = hostName == nil ? Reachability() : Reachability(hostname: hostName!)
    self.reachability = reachability

    if useClosures {
        reachability?.whenReachable = { reachability in
            DispatchQueue.main.async {
                self.updateLabelColourWhenReachable(reachability)
            }
        }
        reachability?.whenUnreachable = { reachability in
            DispatchQueue.main.async {
                self.updateLabelColourWhenNotReachable(reachability)
            }
        }
    } else {
        NotificationCenter.default.addObserver(self, selector: #selector(VC22.reachabilityChanged(_:)), name: ReachabilityChangedNotification, object: reachability)
    }
}

func startNotifier() {
    print("--- start notifier")
    do {
        try reachability?.startNotifier()
    } catch {
        networkStatus.textColor = .red
        networkStatus.text = "Unable to start\nnotifier"
        return
    }
}

func stopNotifier() {
    print("--- stop notifier")
    reachability?.stopNotifier()
    NotificationCenter.default.removeObserver(self, name: ReachabilityChangedNotification, object: nil)
    reachability = nil
}

func updateLabelColourWhenReachable(_ reachability: Reachability) {
    print("\(reachability.description) - \(reachability.currentReachabilityString)")
    if reachability.isReachableViaWiFi {
        self.networkStatus.textColor = .green
    } else {
        self.networkStatus.textColor = .blue
    }

    self.networkStatus.text = reachability.currentReachabilityString
}

func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
    print("\(reachability.description) - \(reachability.currentReachabilityString)")

    self.networkStatus.textColor = .red

    self.networkStatus.text = reachability.currentReachabilityString
}


func reachabilityChanged(_ note: Notification) {
    let reachability = note.object as! Reachability

    if reachability.isReachable {
        updateLabelColourWhenReachable(reachability)
    } else {
        updateLabelColourWhenNotReachable(reachability)
    }
}

deinit {
    stopNotifier()
}

}

這工作正常,但我只需要一個布林值即可告訴我是否已連線,可以通過應用程式重用

當前我正在使用下面的類:UPDATE
import Foundation
import SystemConfiguration

public class Reachability {

    class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
        zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
                SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
            }
        }

        var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
            return false
        }

        let isReachable = flags == .reachable
        let needsConnection = flags == .connectionRequired

        return isReachable && !needsConnection

    }
}

並在如下所示的viewControllers中使用:
 if Reachability.isConnectedToNetwork() == true {
        print("Internet connection OK")

      JSONParseFunction()

} else {
    print("Internet connection FAILED")
    let alert = UIAlertView(title: "You are not connect to internet", message: "please check you connectivity", delegate: nil, cancelButtonTitle: "OK")
    alert.show()
}

這樣,我只需要檢查網際網路,就需要同時檢查主機和網際網路

解決辦法

是否有理由不只是將其放在AppDelegate中並訂閱那裡的觀察者,而不是在特定的vc上這樣做?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        prepareReachabilityObserver()
        return true
    }

    private func prepareReachabilityObserver() {
        AppDelegate.reachability.whenUnreachable = { reachability in
            DispatchQueue.main.async {
                print("Not reachable")
            }
        }

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

host verification extension部分,我可能會喜歡這樣的東西:
extension UIViewController {
    internal func isReachable() -> Bool {
            //this is the function you already have.
    }
}

然後您可以在每個ViewController中使用
self.isReachable() //'self' is a UIViewController in this case.

除此之外,由於您似乎已經解決了這個問題,因此我很難理解您的問題。

編輯:我想我現在明白你的問題。您要檢查是否可以訪問以及傳遞的主機名是否也可以訪問。
我認為最好不要同時處理這兩個問題,因為一個是可達性問題(“我可以得到傳出的連線嗎?”),另一個是連線問題(“我可以得到一個響應嗎?或“此請求是否超時?”)。

我目前處理它的方式是通過AppDelegate之類的Reachability,然後以逐個請求的方式處理超時(然後可以在網路資料範圍內進行概括)。
更具體:AppDelegate設定可達性。然後,我有一個RequestsManager,它使用配置的timeout處理服務呼叫。

然後,您可以執行以下操作:
RequestManager.makeRequest("https://an.endpoint.of.yours",
        onSuccess: {},
        onFailure: { //Here goes your timeout behaviour.
})

我在哪裡傳遞主機名?
老實說,我認為這是不必要的行為。您不先try to open door,然後您open door。您只是嘗試看看您是否成功。都一樣您嘗試發出請求,成功了嗎?太棒了不是嗎相應地處理。如果失敗是由於端點故障或由於沒有有效的資料計劃或網路故障,您(該應用程式)在乎什麼?無論哪種方式,請求都會超時,這就是您所關心的。

同樣,這全部都是假設我確實瞭解您的情況,但我不確定100%。

出處

Have any Question?

Let us answer it!