Überprüfen Sie die Internetverbindung mit Swift

251

Wenn ich versuche, auf meinem iPhone nach einer Internetverbindung zu suchen, werden einige Fehler angezeigt. Kann mir jemand helfen, das zu beheben?

Der Code:

import Foundation
import SystemConfiguration

public class Reachability {

class func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    }

    var flags: SCNetworkReachabilityFlags = 0

    if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
        return false
    }

    let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0

    return (isReachable && !needsConnection) ? true : false
}

}

Die Fehler mit dem Code:

Fehler

Wenn es nicht lesbar ist, lautet Fehler 1:

'Int' kann nicht in 'SCNetworkReachabilityFlags' konvertiert werden.

Fehler 2 & 3:

Es wurde keine Überladung für 'init' gefunden, die die angegebenen Argumente akzeptiert

b3rge
quelle
1
Der Code ähnelt dem, was ich hier vorgeschlagen hatte: stackoverflow.com/a/25623647/1187415 , daher habe ich diesen für Swift 2 aktualisiert.
Martin R
2
Ich habe hier eine voll funktionsfähige Swift 2 Reachability-Implementierung… github.com/ashleymills/Reachability.swift - Sie können diese gerne als Referenz verwenden.
Ashley Mills
1
stackoverflow.com/a/25623647/1187415 Ist jetzt für Swift 3, Xcode 8 Beta 6 aktualisiert.
Martin R
1
Apple bietet ein offizielles Swift-Beispiel an , das Sie auf CocoaPods erhalten können . Es ist mit jedem Swift-Projekt kompatibel.
Cœur

Antworten:

368

Um das in den Kommentaren erwähnte 4G-Problem zu lösen, habe ich die Erreichbarkeitsimplementierung von @AshleyMills als Referenz verwendet und die Erreichbarkeit für Swift 3.1 neu geschrieben:

aktualisiert: Xcode 10.1 • Swift 4 oder höher


Reachability.swift-Datei

import Foundation
import SystemConfiguration

class Reachability {
    var hostname: String?
    var isRunning = false
    var isReachableOnWWAN: Bool
    var reachability: SCNetworkReachability?
    var reachabilityFlags = SCNetworkReachabilityFlags()
    let reachabilitySerialQueue = DispatchQueue(label: "ReachabilityQueue")
    init(hostname: String) throws {
        guard let reachability = SCNetworkReachabilityCreateWithName(nil, hostname) else {
            throw Network.Error.failedToCreateWith(hostname)
        }
        self.reachability = reachability
        self.hostname = hostname
        isReachableOnWWAN = true
        try start()
    }
    init() throws {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let reachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            throw Network.Error.failedToInitializeWith(zeroAddress)
        }
        self.reachability = reachability
        isReachableOnWWAN = true
        try start()
    }
    var status: Network.Status {
        return  !isConnectedToNetwork ? .unreachable :
                isReachableViaWiFi    ? .wifi :
                isRunningOnDevice     ? .wwan : .unreachable
    }
    var isRunningOnDevice: Bool = {
        #if targetEnvironment(simulator)
            return false
        #else
            return true
        #endif
    }()
    deinit { stop() }
}

extension Reachability {

    func start() throws {
        guard let reachability = reachability, !isRunning else { return }
        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
        guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
            throw Network.Error.failedToSetCallout
        }
        guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
            throw Network.Error.failedToSetDispatchQueue
        }
        reachabilitySerialQueue.async { self.flagsChanged() }
        isRunning = true
    }

    func stop() {
        defer { isRunning = false }
        guard let reachability = reachability else { return }
        SCNetworkReachabilitySetCallback(reachability, nil, nil)
        SCNetworkReachabilitySetDispatchQueue(reachability, nil)
        self.reachability = nil
    }

    var isConnectedToNetwork: Bool {
        return isReachable &&
               !isConnectionRequiredAndTransientConnection &&
               !(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
    }

    var isReachableViaWiFi: Bool {
        return isReachable && isRunningOnDevice && !isWWAN
    }

    /// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
    var flags: SCNetworkReachabilityFlags? {
        guard let reachability = reachability else { return nil }
        var flags = SCNetworkReachabilityFlags()
        return withUnsafeMutablePointer(to: &flags) {
            SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))
            } ? flags : nil
    }

    /// compares the current flags with the previous flags and if changed posts a flagsChanged notification
    func flagsChanged() {
        guard let flags = flags, flags != reachabilityFlags else { return }
        reachabilityFlags = flags
        NotificationCenter.default.post(name: .flagsChanged, object: self)
    }

    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var transientConnection: Bool { return flags?.contains(.transientConnection) == true }

    /// The specified node name or address can be reached using the current network configuration.
    var isReachable: Bool { return flags?.contains(.reachable) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
    var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
    var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
    var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
    var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }

    /// The specified node name or address is one that is associated with a network interface on the current system.
    var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }

    /// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
    var isDirect: Bool { return flags?.contains(.isDirect) == true }

    /// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
    var isWWAN: Bool { return flags?.contains(.isWWAN) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var isConnectionRequiredAndTransientConnection: Bool {
        return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
    }
}

func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    guard let info = info else { return }
    DispatchQueue.main.async {
        Unmanaged<Reachability>
            .fromOpaque(info)
            .takeUnretainedValue()
            .flagsChanged()
    }
}

extension Notification.Name {
    static let flagsChanged = Notification.Name("FlagsChanged")
}

struct Network {
    static var reachability: Reachability!
    enum Status: String {
        case unreachable, wifi, wwan
    }
    enum Error: Swift.Error {
        case failedToSetCallout
        case failedToSetDispatchQueue
        case failedToCreateWith(String)
        case failedToInitializeWith(sockaddr_in)
    }
}

Verwendung

Initialisieren Sie es in Ihrer didDinegate.swift didFinishLaunchingWithOptions-Methode und behandeln Sie alle Fehler, die auftreten können:

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        do {
            try Network.reachability = Reachability(hostname: "www.google.com")
        }
        catch {
            switch error as? Network.Error {
            case let .failedToCreateWith(hostname)?:
                print("Network error:\nFailed to create reachability object With host named:", hostname)
            case let .failedToInitializeWith(address)?:
                print("Network error:\nFailed to initialize reachability object With address:", address)
            case .failedToSetCallout?:
                print("Network error:\nFailed to set callout")
            case .failedToSetDispatchQueue?:
                print("Network error:\nFailed to set DispatchQueue")
            case .none:
                print(error)
            }
        }
        return true
    }
}

Und ein View Controller-Beispiel:

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default
            .addObserver(self,
                         selector: #selector(statusManager),
                         name: .flagsChanged,
                         object: nil)
        updateUserInterface()
    }
    func updateUserInterface() {
        switch Network.reachability.status {
        case .unreachable:
            view.backgroundColor = .red
        case .wwan:
            view.backgroundColor = .yellow
        case .wifi:
            view.backgroundColor = .green
        }
        print("Reachability Summary")
        print("Status:", Network.reachability.status)
        print("HostName:", Network.reachability.hostname ?? "nil")
        print("Reachable:", Network.reachability.isReachable)
        print("Wifi:", Network.reachability.isReachableViaWiFi)
    }
    @objc func statusManager(_ notification: Notification) {
        updateUserInterface()
    }
}

Beispielprojekt

Leo Dabus
quelle
2
Sie müssen `== 0` aus dem if SCNetworkReachabilityGetFlags(…)as entfernen, da xCode einen Bool in der neuesten Version zurückgibt.
Melvin
64
Dies ist NICHT korrekt, wie @NickM erwähnt. Funktioniert nicht für zelluläre Verbindungen . Benutze das nicht. Ich bin überrascht, dass es so viele Stimmen gibt, vielleicht ist dies ab iOS 9 neu ... aber ich denke nicht.
Jordan Smith
1
Funktioniert nicht auf IOS9, hat es auf die sehr schwierige Weise herausgefunden - App im Laden ... also denke ich, auch wenn es nicht 100% genau ist und für einige funktioniert, ist es bestenfalls inkonsistent, also wer auch immer Risiken eingehen möchte, möchte es vielleicht auch auf ein Pferd oder einen Hund zu wetten, wenn sie Glück haben.
Nick M
2
@NickM - das erklärt, warum so viele Stimmen abgegeben wurden. @ Leo Es könnte eine gute Idee sein, Ihre Antwort für iOS 9 zu aktualisieren, um zu verhindern, dass andere Personen in dieselbe Falle geraten. Ich kann bestätigen, dass es unter iOS 9 (zumindest in einigen Situationen) nicht funktioniert. Der Wechsel zu github.com/ashleymills/Reachability.swift funktioniert jedoch einwandfrei.
Jordan Smith
1
Ja, ich sehe, es wurde in der iOS10-Filiale herausgebracht
Ace Green
224

Für Swift 3, Swift 4 (Arbeiten mit Mobilfunk und Wi-Fi):

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
        }

        /* Only Working for WIFI
        let isReachable = flags == .reachable
        let needsConnection = flags == .connectionRequired

        return isReachable && !needsConnection
        */

        // Working for Cellular and WIFI
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        let ret = (isReachable && !needsConnection)

        return ret

    }
}

Verwendung:

if Reachability.isConnectedToNetwork(){
    print("Internet Connection Available!")
}else{
    print("Internet Connection not Available!")
}
Rajamohan S.
quelle
3
Diese Lösung + CoreTelephony (CTTelephonyNetworkInfo (). CurrentRadioAccessTechnology) ist die beste Lösung, um den aktuellen Netzwerktyp abzurufen, ohne auf Bibliotheken von Drittanbietern angewiesen zu sein.
Alejandro Jiménez Agudo
3
Funktioniert für Mobilfunk und WiFi mit Swift 3.1! Funktioniert getestet auf iPhone 6 und 7. Wenn Cellular Off ist, wird "..Connection not Available" angezeigt. Wenn ich den Flugzeugmodus einschalte, bekomme ich das gleiche "... nicht verfügbar". Wenn ich das Mobiltelefon ausgeschaltet und das WLAN eingeschaltet habe, wird ".. Verbindung verfügbar" angezeigt. Wenn ich das WLAN ausschalte und das Mobiltelefon einschalte, wird ".. Verbindung verfügbar" angezeigt. Beachten Sie, dass meine Mobilfunkverbindung LTE ist
Brian
1
Hallo, dies funktioniert nicht unter iOS 11, Flugzeugmodus auf einem physischen Gerät. Im Flugzeugmodus ist isReachable immer noch wahr ... eine Idee warum?
Lawrence Tan
3
Dies funktioniert in allen Szenarien perfekt für mich. Es ist auch mit iOS 12 auf dem iPhone 6 getestet.
r3dm4n
3
Dies funktioniert nicht, wenn ich mit einem WLAN-Netzwerk ohne Internetverbindung verbunden bin
Nathan Barreto
58

Erstellen Sie eine neue Swift-Datei in Ihrem Projekt und benennen Sie sie Reachability.swift. Schneiden Sie den folgenden Code aus und fügen Sie ihn ein, um Ihre Klasse zu erstellen.

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(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
            SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0))
        }

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

        let isReachable = flags == .Reachable
        let needsConnection = flags == .ConnectionRequired

        return isReachable && !needsConnection

    }
}

Mit diesem Code können Sie die Internetverbindung an einer beliebigen Stelle in Ihrem Projekt überprüfen:

if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
}

Wenn der Benutzer nicht mit dem Internet verbunden ist, möchten Sie ihm möglicherweise einen Warndialog anzeigen, um ihn zu benachrichtigen.

if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
    var alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
    alert.show()
}

Erläuterung:

Wir machen eine wiederverwendbare öffentliche Klasse und eine Methode, die überall im Projekt verwendet werden kann, um die Internetverbindung zu überprüfen. Wir müssen Foundation- und Systemkonfigurations-Frameworks hinzufügen.

In der öffentlichen Klasse Reachability gibt die Methode isConnectedToNetwork() -> Bool { }einen Bool-Wert für die Internetverbindung zurück. Wir verwenden eine if-Schleife, um die erforderlichen Aktionen für den Fall auszuführen. Ich hoffe das reicht. Prost!

AG
quelle
4
Wenn Sie eine Lösung geben, versuchen Sie bitte, diese ein wenig zu erklären. Es ist nicht wichtig, eine Lösung zu finden, aber es ist wichtiger, Ihren Lesern die Lösung und ihr Konzept verständlich zu machen.
G.Abhisek
1
Ich bin neu in der iOS-Programmierung. Warum müssen wir zu diesem Zweck eine C-Struktur initialisieren? In welchen Fällen können wir C-Strukturen verwenden?
G.Abhisek
1
Ich habe dies nur zu Testzwecken auf "viewdidload" gesetzt. Ich öffne die App und OK, habe Internet, aber wenn ich mein Internet abschieße, zeigt es mir weiterhin, dass ich Internet habe ... das ist hartnäckig? oder muss ich jedes mal "action" rufen?
Daniel Arantes Loverde
16
@AlvinGeorge Dies funktioniert NICHT , wenn eine Verbindung zu einem Mobilfunknetz besteht. Dies funktioniert nur bei Verwendung von WLAN. An alle anderen - Sie möchten dies nicht in Ihrer App verwenden! @ Alvin - kann ich vorschlagen, dass Sie Ihre Antwort aktualisieren oder entfernen? Mit 19 Stimmen ist es für andere Entwickler sehr irreführend, in die gleiche Falle zu tappen.
Jordan Smith
@Jordan: Diese Methode verwendet das Standard-Apple-Framework für den Netzwerkstatus. Dies kann sich mit neuen iOS-Versionen ändern. Daher empfehle ich Ihnen, die Erreichbarkeitsklasse von Ashely Mill zu überprüfen und zu implementieren. Ich habe eine abhängigkeitsfreie Implementierung durchgeführt und den obigen Link geteilt. Guck dir das mal bitte an.
AG
56

Wenn jemand Alamofire bereits verwendet, dann -

struct Connectivity {
  static let sharedInstance = NetworkReachabilityManager()!
  static var isConnectedToInternet:Bool {
      return self.sharedInstance.isReachable
    }
}

Verwendung:

if Connectivity.isConnectedToInternet {
     print("Connected")
 } else {
     print("No Internet")
}
Jack
quelle
1
Aus der Alamofire-Dokumentation:> Die NetworkReachabilityManager-Klasse wartet auf Änderungen der Erreichbarkeit von Hosts und Adressen für WWAN- und WiFi-Netzwerkschnittstellen. > Die Erreichbarkeit kann verwendet werden, um Hintergrundinformationen darüber zu ermitteln, warum ein Netzwerkvorgang fehlgeschlagen ist, oder um Netzwerkanforderungen erneut zu versuchen, wenn eine Verbindung hergestellt wird. Es sollte nicht verwendet werden, um einen Benutzer daran zu hindern, eine Netzwerkanforderung zu initiieren, da möglicherweise eine erste Anforderung erforderlich ist, um die Erreichbarkeit herzustellen.
Fespinozacast
1
@fespinozacast gut können Sie den Internetverbindungscode in NetworkReachabilityManager.swift überprüfen , was völlig in Ordnung ist :)
Jack
15

Ich habe die Implementierung der Erreichbarkeitsklasse von Ashley Mill ohne Cocoa Pods / Dependancy Manager überprüft. Die Idee ist, die Erreichbarkeitsabhängigkeit im Projekt frei zu machen.

Xcode 7.2 - Swift 2.1

1) https://github.com/ashleymills/Reachability.swift . Download Fügen Sie dem Projekt die Erreichbarkeitsklasse hinzu.

Hinweis: Stellen Sie beim Hinzufügen sicher, dass "Elemente bei Bedarf kopieren" aktiviert ist.

2) Erstellen Sie eine AppManager.swift-Klasse. Diese Klasse wird als öffentliche Modellklasse angeboten, in der öffentliche Methoden und Daten hinzugefügt werden und in jedem VC verwendet werden können.

//  AppManager.swift

import UIKit
import Foundation

class AppManager: NSObject{
    var delegate:AppManagerDelegate? = nil
    private var _useClosures:Bool = false
    private var reachability: Reachability?
    private var _isReachability:Bool = false
    private var _reachabiltyNetworkType :String?

    var isReachability:Bool {
        get {return _isReachability}
    }  
   var reachabiltyNetworkType:String {
    get {return _reachabiltyNetworkType! }
   }   




    // Create a shared instance of AppManager
    final  class var sharedInstance : AppManager {
        struct Static {
            static var instance : AppManager?
        }
        if !(Static.instance != nil) {
            Static.instance = AppManager()

        }
        return Static.instance!
    }

    // Reachability Methods
    func initRechabilityMonitor() {
        print("initialize rechability...")
        do {
            let reachability = try Reachability.reachabilityForInternetConnection()
            self.reachability = reachability
        } catch ReachabilityError.FailedToCreateWithAddress(let address) {
            print("Unable to create\nReachability with address:\n\(address)")
            return
        } catch {}
        if (_useClosures) {
            reachability?.whenReachable = { reachability in
                self.notifyReachability(reachability)
            }
            reachability?.whenUnreachable = { reachability in
                self.notifyReachability(reachability)
            }
        } else {
            self.notifyReachability(reachability!)
        }

        do {
            try reachability?.startNotifier()
        } catch {
            print("unable to start notifier")
            return
        }


    }        
    private func notifyReachability(reachability:Reachability) {
        if reachability.isReachable() {
            self._isReachability = true

//Determine Network Type 
      if reachability.isReachableViaWiFi() {   
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WIFI_NETWORK.rawValue
      } else {
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WWAN_NETWORK.rawValue
      }

        } else {
            self._isReachability = false
self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.OTHER.rawValue

        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: ReachabilityChangedNotification, object: reachability)
    }
    func reachabilityChanged(note: NSNotification) {
        let reachability = note.object as! Reachability
        dispatch_async(dispatch_get_main_queue()) {
            if (self._useClosures) {
                self.reachability?.whenReachable = { reachability in
                    self.notifyReachability(reachability)
                }
                self.reachability?.whenUnreachable = { reachability in
                    self.notifyReachability(reachability)
                }
            } else {
                self.notifyReachability(reachability)
            }
            self.delegate?.reachabilityStatusChangeHandler(reachability)
        }
    }
    deinit {
        reachability?.stopNotifier()
        if (!_useClosures) {
            NSNotificationCenter.defaultCenter().removeObserver(self, name: ReachabilityChangedNotification, object: nil)
        }
    }
}

3) Machen Sie eine Delegiertenklasse. Ich verwende die Delegate-Methode, um den Konnektivitätsstatus zu benachrichtigen.

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

4) Machen Sie die übergeordnete Klasse von UIViewController (Vererbungsmethode). Die übergeordnete Klasse verfügt über Methoden, auf die alle untergeordneten VCs zugreifen können.

//  UIappViewController.swift

    import UIKit

    class UIappViewController: UIViewController,AppManagerDelegate {
        var manager:AppManager = AppManager.sharedInstance

        override func viewDidLoad() {
            super.viewDidLoad()
            manager.delegate = self
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        func reachabilityStatusChangeHandler(reachability: Reachability) {
            if reachability.isReachable() {
                print("isReachable")
            } else {
                print("notReachable")
            }
        }
    }

5) Starten Sie die Echtzeit-Überwachung der Internetverbindung in AppDelegate.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    AppManager.sharedInstance.initRechabilityMonitor()
return true
}

6) Ich habe eine Swift File Name AppReference hinzugefügt, um konstante Aufzählungswerte zu speichern.

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

  case WIFI_NETWORK = "Wifi"
  case WWAN_NETWORK = "Cellular"
  case OTHER = "Other"

}

7) Auf ViewController (z. B. Sie möchten eine API nur aufrufen, wenn ein Netzwerk verfügbar ist).

//  ViewController.swift

        import UIKit

class ViewController: UIappViewController {
  var reachability:Reachability?

  override func viewDidLoad() {
    super.viewDidLoad()
    manager.delegate = self

    if(AppManager.sharedInstance.isReachability)
    {
      print("net available")
      //call API from here.

    } else {
      dispatch_async(dispatch_get_main_queue()) {
        print("net not available")
        //Show Alert
      }
    }


    //Determine Network Type
    if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
    {
      print(".Wifi")
    }
    else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
    {
      print(".Cellular")
    }
    else {
      dispatch_async(dispatch_get_main_queue()) {
        print("Network not reachable")
      }
    }

  }
  override func viewWillAppear(animated: Bool) {
  }
  override func didReceiveMemoryWarning() {
  }
}

Das Beispiel kann heruntergeladen werden @ https://github.com/alvinreuben/Reachability-Sample

Upgrade auf Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3

AG
quelle
In Schritt 4 ... dem UIappViewController.swift, warum brauchen wir diese Klasse?
Learn2Code
UIappViewController.swift funktioniert nicht mit UICollectionViewController. Wenn Sie also eine Ansicht mit UICollectionViewController haben, können Sie UIappViewController nicht erben!?
Learn2Code
12

Apple hat Network Framework in iOS12 eingeführt.

import Foundation
import Network

class NetworkReachability {

   var pathMonitor: NWPathMonitor!
   var path: NWPath?
   lazy var pathUpdateHandler: ((NWPath) -> Void) = { path in
    self.path = path
    if path.status == NWPath.Status.satisfied {
        print("Connected")
    } else if path.status == NWPath.Status.unsatisfied {
        print("unsatisfied")
    } else if path.status == NWPath.Status.requiresConnection {
        print("requiresConnection")
    } 
}

let backgroudQueue = DispatchQueue.global(qos: .background)

init() {
    pathMonitor = NWPathMonitor()
    pathMonitor.pathUpdateHandler = self.pathUpdateHandler
    pathMonitor.start(queue: backgroudQueue)
   } 

 func isNetworkAvailable() -> Bool {
        if let path = self.path {
           if path.status == NWPath.Status.satisfied {
            return true
          }
        }
       return false
   }
 }
Yogendra Singh
quelle
var path: NWPath? ist null. Wie initialisieren wir diese Eigenschaft?
Vitya Shurapov
@VityaShurapov Durch Zuweisen eines Pfads erhalten Sie den Pfad pathUpdateHandler.
Yogendra Singh
Das sieht schick aus, aber ich habe festgestellt (zumindest im Simulator), dass ich einen Rückruf bekomme, wenn ich mein Laptop-WLAN aus- und wieder einschalte, aber es heißt "unbefriedigt", und danach wird der Rückruf nie mehr aufgerufen.
Zaitsman
Beim Ein- und Ausschalten des Mobilfunknetzes wird der Handler nur einmal zum Ein- und Ausschalten ausgelöst. Wenn WiFi ein- und ausgeschaltet wird, erhalte ich zwei identische Auslöser für Ein / Aus (alle Eigenschaften sind identisch). Warum ist das so?
Geohei
pathUpdateHandlerwird eine starke Referenz mit einführen self, hinzufügen [weak self], um es zu lösen :)
Andrea de Marco
11

Verwenden Sie dies für Swift-5 +

import Foundation
import UIKit
import SystemConfiguration

public class InternetConnectionManager {


    private init() {

    }

    public static func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {

            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

                SCNetworkReachabilityCreateWithAddress(nil, $0)

            }

        }) else {

            return false
        }
        var flags = SCNetworkReachabilityFlags()
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        return (isReachable && !needsConnection)
    }

}

Verwendung:

InternetConnectionManager.isConnectedToNetwork{
    print("Connected")
}else{
    print("Not Connected")
}

Oder verwenden Sie dies einfach frameworkfür mehrUtilities : Link

Jamil Hasnine Tamim
quelle
@ DocAsh59 :) Willkommen! Viel Spaß beim Codieren!
Jamil Hasnine Tamim
Ich verstehe die Verwendung nicht. Der Compiler zeigt den Fehler "An Aufruf übergebene Argumente, die keine Argumente annehmen" an.
Roland Lariotte
1
@RolandLariotte Sie klassifizieren einfach in Ihrem Projekt "InternetConnectionManager" und rufen dann an, wo Sie wollen!
Jamil Hasnine Tamim
Funktioniert perfekt. Denken Sie, dass dieser Code reaktiver sein kann, wenn Sie Combine verwenden und einen AnyPublisher <Bool, Never> zurückgeben? Könnten Sie es so schreiben?
Roland Lariotte
@ RolandLariotte Ja könnte sein. Ich werde später einen weiteren Code schreiben. Danke und vergiss nicht zu unterstützen! :)
Jamil Hasnine Tamim
7

Hab das nur für mich selbst herausgefunden.

Xcode: 7.3.1, iOS 9.3.3

Mit ashleymills / Reachability.swift als Reachability.swift in meinem Projekt habe ich die folgende Funktion erstellt:

func hasConnectivity() -> Bool {
    do {
        let reachability: Reachability = try Reachability.reachabilityForInternetConnection()
        let networkStatus: Int = reachability.currentReachabilityStatus.hashValue

        return (networkStatus != 0)
    }
    catch {
        // Handle error however you please
        return false
    }
}

Rufen hasConnectivity()Sie einfach an, wo immer Sie nach einer Verbindung suchen müssen. Dies funktioniert sowohl für Wifi als auch für Cellular.


Hinzufügen von Reachability.swift von ashleymills, damit die Benutzer nicht zwischen Standorten wechseln müssen:

Copyright (c) 2014, Ashley Mills
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

// Reachability.swift version 2.2beta2

import SystemConfiguration
import Foundation

public enum ReachabilityError: ErrorType {
    case FailedToCreateWithAddress(sockaddr_in)
    case FailedToCreateWithHostname(String)
    case UnableToSetCallback
    case UnableToSetDispatchQueue
}

public let ReachabilityChangedNotification = "ReachabilityChangedNotification"

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
    let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

    dispatch_async(dispatch_get_main_queue()) {
        reachability.reachabilityChanged(flags)
    }
}


public class Reachability: NSObject {

    public typealias NetworkReachable = (Reachability) -> ()
    public typealias NetworkUnreachable = (Reachability) -> ()

    public enum NetworkStatus: CustomStringConvertible {

        case NotReachable, ReachableViaWiFi, ReachableViaWWAN

        public var description: String {
            switch self {
            case .ReachableViaWWAN:
                return "Cellular"
            case .ReachableViaWiFi:
                return "WiFi"
            case .NotReachable:
                return "No Connection"
            }
        }
    }

    // MARK: - *** Public properties ***
    public var whenReachable: NetworkReachable?
    public var whenUnreachable: NetworkUnreachable?
    public var reachableOnWWAN: Bool
    public var notificationCenter = NSNotificationCenter.defaultCenter()

    public var currentReachabilityStatus: NetworkStatus {
        if isReachable() {
            if isReachableViaWiFi() {
                return .ReachableViaWiFi
            }
            if isRunningOnDevice {
                return .ReachableViaWWAN
            }
        }
        return .NotReachable
    }

    public var currentReachabilityString: String {
        return "\(currentReachabilityStatus)"
    }

    private var previousFlags: SCNetworkReachabilityFlags?

    // MARK: - *** Initialisation methods ***

    required public init(reachabilityRef: SCNetworkReachability) {
        reachableOnWWAN = true
        self.reachabilityRef = reachabilityRef
    }

    public convenience init(hostname: String) throws {

        let nodename = (hostname as NSString).UTF8String
        guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }

        self.init(reachabilityRef: ref)
    }

    public class func reachabilityForInternetConnection() throws -> Reachability {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let ref = withUnsafePointer(&zeroAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else { throw ReachabilityError.FailedToCreateWithAddress(zeroAddress) }

        return Reachability(reachabilityRef: ref)
    }

    public class func reachabilityForLocalWiFi() throws -> Reachability {

        var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
        localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
        localWifiAddress.sin_family = sa_family_t(AF_INET)

        // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
        let address: UInt32 = 0xA9FE0000
        localWifiAddress.sin_addr.s_addr = in_addr_t(address.bigEndian)

        guard let ref = withUnsafePointer(&localWifiAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else { throw ReachabilityError.FailedToCreateWithAddress(localWifiAddress) }

        return Reachability(reachabilityRef: ref)
    }

    // MARK: - *** Notifier methods ***
    public func startNotifier() throws {

        guard !notifierRunning else { return }

        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())

        if !SCNetworkReachabilitySetCallback(reachabilityRef!, callback, &context) {
            stopNotifier()
            throw ReachabilityError.UnableToSetCallback
        }

        if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef!, reachabilitySerialQueue) {
            stopNotifier()
            throw ReachabilityError.UnableToSetDispatchQueue
        }

        // Perform an intial check
        dispatch_async(reachabilitySerialQueue) { () -> Void in
            let flags = self.reachabilityFlags
            self.reachabilityChanged(flags)
        }

        notifierRunning = true
    }

    public func stopNotifier() {
        defer { notifierRunning = false }
        guard let reachabilityRef = reachabilityRef else { return }

        SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
        SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
    }

    // MARK: - *** Connection test methods ***
    public func isReachable() -> Bool {
        let flags = reachabilityFlags
        return isReachableWithFlags(flags)
    }

    public func isReachableViaWWAN() -> Bool {

        let flags = reachabilityFlags

        // Check we're not on the simulator, we're REACHABLE and check we're on WWAN
        return isRunningOnDevice && isReachable(flags) && isOnWWAN(flags)
    }

    public func isReachableViaWiFi() -> Bool {

        let flags = reachabilityFlags

        // Check we're reachable
        if !isReachable(flags) {
            return false
        }

        // Must be on WiFi if reachable but not on an iOS device (i.e. simulator)
        if !isRunningOnDevice {
            return true
        }

        // Check we're NOT on WWAN
        return !isOnWWAN(flags)
    }

    // MARK: - *** Private methods ***
    private var isRunningOnDevice: Bool = {
        #if (arch(i386) || arch(x86_64)) && os(iOS)
            return false
        #else
            return true
        #endif
    }()

    private var notifierRunning = false
    private var reachabilityRef: SCNetworkReachability?
    private let reachabilitySerialQueue = dispatch_queue_create("uk.co.ashleymills.reachability", DISPATCH_QUEUE_SERIAL)

    private func reachabilityChanged(flags: SCNetworkReachabilityFlags) {

        guard previousFlags != flags else { return }

        if isReachableWithFlags(flags) {
            if let block = whenReachable {
                block(self)
            }
        } else {
            if let block = whenUnreachable {
                block(self)
            }
        }

        notificationCenter.postNotificationName(ReachabilityChangedNotification, object:self)

        previousFlags = flags
    }

    private func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {

        if !isReachable(flags) {
            return false
        }

        if isConnectionRequiredOrTransient(flags) {
            return false
        }

        if isRunningOnDevice {
            if isOnWWAN(flags) && !reachableOnWWAN {
                // We don't want to connect when on 3G.
                return false
            }
        }

        return true
    }

    // WWAN may be available, but not active until a connection has been established.
    // WiFi may require a connection for VPN on Demand.
    private func isConnectionRequired() -> Bool {
        return connectionRequired()
    }

    private func connectionRequired() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags)
    }

    // Dynamic, on demand connection?
    private func isConnectionOnDemand() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags) && isConnectionOnTrafficOrDemand(flags)
    }

    // Is user intervention required?
    private func isInterventionRequired() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags) && isInterventionRequired(flags)
    }

    private func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
        #if os(iOS)
            return flags.contains(.IsWWAN)
        #else
            return false
        #endif
    }
    private func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.Reachable)
    }
    private func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionRequired)
    }
    private func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.InterventionRequired)
    }
    private func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionOnTraffic)
    }
    private func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionOnDemand)
    }
    func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
        return !flags.intersect([.ConnectionOnTraffic, .ConnectionOnDemand]).isEmpty
    }
    private func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.TransientConnection)
    }
    private func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.IsLocalAddress)
    }
    private func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.IsDirect)
    }
    private func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
        let testcase:SCNetworkReachabilityFlags = [.ConnectionRequired, .TransientConnection]
        return flags.intersect(testcase) == testcase
    }

    private var reachabilityFlags: SCNetworkReachabilityFlags {

        guard let reachabilityRef = reachabilityRef else { return SCNetworkReachabilityFlags() }

        var flags = SCNetworkReachabilityFlags()
        let gotFlags = withUnsafeMutablePointer(&flags) {
            SCNetworkReachabilityGetFlags(reachabilityRef, UnsafeMutablePointer($0))
        }

        if gotFlags {
            return flags
        } else {
            return SCNetworkReachabilityFlags()
        }
    }

    override public var description: String {

        var W: String
        if isRunningOnDevice {
            W = isOnWWAN(reachabilityFlags) ? "W" : "-"
        } else {
            W = "X"
        }
        let R = isReachable(reachabilityFlags) ? "R" : "-"
        let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
        let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
        let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
        let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
        let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
        let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
        let d = isDirect(reachabilityFlags) ? "d" : "-"

        return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
    }

    deinit {
        stopNotifier()

        reachabilityRef = nil
        whenReachable = nil
        whenUnreachable = nil
    }
}
cmeadows
quelle
@ Xitcod13 Dies würde mit einem 4G-Netzwerk funktionieren. Es wird jedoch empfohlen, den Preflight NICHT zu testen. Behandeln Sie die Ausnahme, die bei Ihrem Verbindungsversuch ausgelöst wurde, anstatt einen Reachability.swift-Testfall zu verwenden.
cmeadows
Reachabilty.swift hat Probleme mit Swift 3
Famic Tech
Funktioniert gut mit dem Swift 3, wechseln Sie einfach let reachability: Reachability = try Reachability.reachabilityForInternetConnection()zulet reachability: Reachability = try Reachability()!
Davidethell
7

Obwohl es Ihre Frage nicht direkt beantwortet, möchte ich erwähnen, dass Apple kürzlich diesen Vortrag gehalten hat:

https://developer.apple.com/videos/play/wwdc2018/714/

Gegen 09:55 Uhr spricht er darüber, wie man das macht, worüber man fragt:

  1. Verbindung prüfen
  2. Wenn Verbindung -> etwas tun
  3. Wenn keine Verbindung besteht -> etwas anderes tun (warten? Wiederholen?)

Dies hat jedoch einige Fallstricke:

  • Was ist, wenn in Schritt 2 angegeben wird, dass eine Verbindung besteht, 0,5 Sekunden später jedoch keine?
  • Was ist, wenn sich der Benutzer hinter einem Proxy befindet?
  • Was ist, wenn einige Antworten hier die Konnektivität nicht richtig bestimmen können? (Ich bin sicher, wenn Sie Ihre Verbindung schnell wechseln, zu Wi-Fi gehen und sie ausschalten (machen Sie es einfach kompliziert), kann es fast nie richtig feststellen, ob ich eine Verbindung habe oder nicht).
  • Zitat aus dem Video: "Es gibt keine Möglichkeit zu garantieren, ob eine zukünftige Operation erfolgreich sein wird oder nicht"

Die folgenden Punkte sind laut Apple einige bewährte Methoden:

Laut dem Vortrag sollte es keinen Grund geben, vorab zu prüfen, ob Sie eine Internetverbindung haben oder nicht, da diese zum Zeitpunkt des Sendens Ihrer Anfrage an den Server möglicherweise nicht korrekt ist .

J. Doe
quelle
2

Ich habe meine eigene Lösung mit NSTimer und Alamofire erstellt:

import Alamofire

public class ConnectionHelper: NSObject {
    var request: Alamofire.Request?

    func isInternetConnected(completionHandler: Bool -> Void) {
        NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "requestTimeout", userInfo: nil, repeats: false)

        request = Alamofire
            .request(
                Method.HEAD,
                "http://www.testurl.com"
            )
            .response { response in
                if response.3?.code == -999 {
                    completionHandler(
                        false
                    )
                } else {
                    completionHandler(
                        true
                    )
                }
        }
    }

    func requestTimeout() {
        request!.cancel()
    }
}

Der NSTimer wird als Zeitlimit verwendet und wurde aufgrund unzuverlässiger Ergebnisse bei Verwendung des Alamofire-Zeitlimits verwendet. Die Anfrage sollte an eine URL gerichtet werden, der Sie als zuverlässig vertrauen, z. B. Ihren eigenen Server oder den Server, auf dem die Dienste gehostet werden, von denen Sie abhängig sind.

Wenn der Timer abläuft, wird die Anforderung abgebrochen und die Ergebnisse werden mithilfe eines Abschlusshandlers zurückgegeben.

Verwendung:

ConnectionHelper().isInternetConnected() { internetConnected in
    if internetConnected {
        // Connected
    } else {
        // Not connected
    }
}
Mark Tickner
quelle
1
Was ist, wenn der Website-Server nicht verfügbar ist?
TechBee
Dann requestTimeout()würde aufgerufen werden, nachdem das angegebene Timeout erreicht wurde
Mark Tickner
Danke Mark! Ihr Ansatz sollte generisch sein !!
TechBee
1
Inwiefern? Die Seite, die verwendet wird? Die Idee wäre, dass die verwendete Website eine ist, von der Ihre App abhängig ist
Mark Tickner
Wahrscheinlich ist es keine gute Idee, eine Netzwerkverbindung herzustellen und zu prüfen, ob eine Antwort eingeht oder nicht. Es gibt einfach zu viele Was-wäre-wenn-Fragen
GoodSp33d
2

Wenn Sie Alamofire verwenden, können Sie Folgendes tun:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15 //Set timeouts in sec
configuration.timeoutIntervalForResource = 15

let alamoFireManager = Alamofire.Manager(configuration:configuration)
alamoFireManager?.request(.GET, "https://yourURL.com", parameters: headers, encoding: .URL)
                     .validate()
                              .responseJSON { response in

                                if let error = response.result.error {
                                   switch error.code{
                                    case -1001:
                                        print("Slow connection")
                                        return
                                    case -1009:
                                        print("No Connection!")
                                        return
                                    default: break
                                    }
                                }
Illya Krit
quelle
1

hier meine lösung für swift 2.3 mit der lib ( Reachability.swift )

Gehen Sie in Ihre Podfileund fügen Sie hinzu:

pod 'ReachabilitySwift', '~> 2.4' // swift 2.3

Dann in deine terminal:

pod install

Erstellen Sie dann eine neue Datei ReachabilityManagerund fügen Sie den folgenden Code hinzu:

import Foundation
import ReachabilitySwift

enum ReachabilityManagerType {
    case Wifi
    case Cellular
    case None
}

class ReachabilityManager {
    static let sharedInstance = ReachabilityManager()

    private var reachability: Reachability!
    private var reachabilityManagerType: ReachabilityManagerType = .None


    private init() {
        do {
            self.reachability = try Reachability.reachabilityForInternetConnection()
        } catch {
            print("Unable to create Reachability")
            return
        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ReachabilityManager.reachabilityChanged(_:)),name: ReachabilityChangedNotification,object: self.reachability)
        do{
            try self.reachability.startNotifier()
        }catch{
            print("could not start reachability notifier")
        }
    }

    @objc private func reachabilityChanged(note: NSNotification) {

        let reachability = note.object as! Reachability

        if reachability.isReachable() {
            if reachability.isReachableViaWiFi() {
                self.reachabilityManagerType = .Wifi
            } else {
                self.reachabilityManagerType = .Cellular
            }
        } else {
            self.reachabilityManagerType = .None
        }
    }
}

extension ReachabilityManager {

    func isConnectedToNetwork() -> Bool {
        return reachabilityManagerType != .None
    }

}

Wie man es benutzt:

Gehen Sie in Ihre AppDelegate.swiftund fügen Sie den folgenden Code hinzu:

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

Wenn Sie dann überprüfen möchten, ob das Gerät mit dem Internet verbunden ist, gehen Sie wie folgt vor:

if ReachabilityManager.sharedInstance.isConnectedToNetwork() {
   // Connected
} else {
  // Not connected
}
Douarbou
quelle
1

Während möglicherweise nicht direkt festgestellt wird, ob das Telefon mit einem Netzwerk verbunden ist, besteht die einfachste (, sauberste?) Lösung darin, Google oder einen anderen Server zu "pingen" (was nur möglich ist, wenn das Telefon mit einem Netzwerk verbunden ist) ):

private var urlSession:URLSession = {
    var newConfiguration:URLSessionConfiguration = .default
    newConfiguration.waitsForConnectivity = false
    newConfiguration.allowsCellularAccess = true
    return URLSession(configuration: newConfiguration)
}()

public func canReachGoogle() -> Bool
{
    let url = URL(string: "https://8.8.8.8")
    let semaphore = DispatchSemaphore(value: 0)
    var success = false
    let task = urlSession.dataTask(with: url!)
    { data, response, error in
        if error != nil
        {
            success = false
        }
        else
        {
            success = true
        }
        semaphore.signal()
    }

    task.resume()
    semaphore.wait()

    return success
}

Wenn Sie befürchten, dass der Server ausfällt oder Ihre IP blockiert, können Sie jederzeit mehrere Server auf ähnliche Weise anpingen und zurückgeben, ob einer von ihnen erreichbar ist. Oder lassen Sie jemanden einen dedizierten Server nur für diesen Zweck einrichten.

AL Strine
quelle
1

Swift 5

import SystemConfiguration    

protocol Utilities {}
extension NSObject: Utilities {
    enum ReachabilityStatus {
        case notReachable
        case reachableViaWWAN
        case reachableViaWiFi
    }

    var currentReachabilityStatus: ReachabilityStatus {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return .notReachable
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return .notReachable
        }

        if flags.contains(.reachable) == false {
            // The target host is not reachable.
            return .notReachable
        }
        else if flags.contains(.isWWAN) == true {
            // WWAN connections are OK if the calling application is using the CFNetwork APIs.
            return .reachableViaWWAN
        }
        else if flags.contains(.connectionRequired) == false {
            // If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
            return .reachableViaWiFi
        }
        else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
            // The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
            return .reachableViaWiFi
        }
        else {
            return .notReachable
        }
    }
}

Verwenden Sie bei jeder Methode die folgende Bedingung

if currentReachabilityStatus == .notReachable {
    // Network Unavailable
 } else {
    // Network Available
 }
Gurjinder Singh
quelle
0

Mit Hilfe des folgenden Codes können Sie die Internetverbindung sowohl für Mobilfunknetze als auch für WLAN überprüfen. Sprache - Swift 3.0

import UIKit
import Foundation
import SystemConfiguration

class NetworkConnection: UIViewController {

  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)

    guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
      $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        SCNetworkReachabilityCreateWithAddress(nil, $0)
      }
    }) else {
      return false
    }

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
      return false
    }
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
  }

  class func checkConnection(sender:UIViewController){
    if NetworkConnection.isConnectedToNetwork() == true {
      print("Connected to the internet")
      //  Do something
    } else {
      print("No internet connection")
      let alertController = UIAlertController(title: "No Internet Available", message: "", preferredStyle: UIAlertControllerStyle.alert)
      let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){(result:UIAlertAction) -> Void in
        return
      }
      alertController.addAction(okAction)
      sender.present(alertController, animated: true, completion: nil)
      //  Do something
    }
  }

}
Ronit
quelle
0

Für Swift 3 konnte ich nicht nur die Erreichbarkeit von RAJAMOHAN-S-Lösungen verwenden, da es "true" zurückgibt, wenn WiFi, aber kein Internet vorhanden ist. Daher habe ich die zweite Validierung über die URLSession-Klasse und den Completion-Handler implementiert.

Hier ist die ganze Klasse.

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
}

// Working for Cellular and WIFI
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
let ret = (isReachable && !needsConnection)

return ret
}



class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {

// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
  completionHandler(false)
  return
}

// 2. Check the Internet Connection
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
  webAddress = webSiteToPing!
}

guard let url = URL(string: webAddress) else {
  completionHandler(false)
  print("could not create url from: \(webAddress)")
  return
}

let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
  if error != nil || response == nil {
    completionHandler(false)
  } else {
    completionHandler(true)
  }
})

  task.resume()
}
}

Und Sie nennen das zum Beispiel so:

Reachability.isInternetAvailable(webSiteToPing: nil) { (isInternetAvailable) in
  guard isInternetAvailable else {
    // Inform user for example
    return
  }

  // Do some action if there is Internet
}
Pavle Mijatovic
quelle
0

Das ist meine Version. Im Wesentlichen bringt es nichts Neues. Ich habe es an UIDevice gebunden.

import UIKit
import SystemConfiguration

extension UIDevice {

    open class var isConnectedToNetwork: Bool {
        get {
            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)

            guard
                let defaultRouteReachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
                    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                        SCNetworkReachabilityCreateWithAddress(nil, $0)
                    }
                }),
                var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags() as SCNetworkReachabilityFlags?,
                SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
                else { return false }

            return flags.contains(.reachable) && !flags.contains(.connectionRequired)
        }
    }

}

print("Network status availability: " + ( UIDevice.isConnectedToNetwork ? "true" : "false" ))
jake1981
quelle
0
struct Connectivity {
        static let sharedInstance = NetworkReachabilityManager()!
        static var isConnectedToInternet:Bool {
            return self.sharedInstance.isReachable
        }
    }

Nennen Sie es jetzt

if Connectivity.isConnectedToInternet{
            call_your_methods_here()
        }else{
            show_alert_for_noInternet()
        }
Raghib Arshi
quelle