Проверьте интернет-соединение с Swift


251

Когда я пытаюсь проверить подключение к Интернету на моем iPhone, я получаю кучу ошибок. Может кто-нибудь помочь мне исправить это?

Код:

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
}

}

Ошибки с кодом:

ошибки

Если это нечитаемо, ошибка 1 говорит:

Int не может быть преобразовано в SCNetworkReachabilityFlags.

Ошибка 2 и 3:

Не удалось найти перегрузку для 'init', который принимает предоставленные аргументы


1
Код выглядит аналогично тому, что я предложил здесь: stackoverflow.com/a/25623647/1187415 , поэтому я обновил его для Swift 2.
Martin R

2
У меня есть полностью рабочая реализация Swift 2 Reachability здесь… github.com/ashleymills/Reachability.swift - не стесняйтесь использовать это в качестве ссылки.
Эшли Миллс

1
stackoverflow.com/a/25623647/1187415 В настоящее время обновляется для Swift 3, Xcode 8 beta 6.
Martin R

1
Apple предоставляет официальный образец Swift , и вы можете получить его на CocoaPods . Он совместим с любым проектом Swift.
Cœur

Ответы:


368

Для решения проблемы 4G, упомянутой в комментариях, я использовал реализацию достижимости @AshleyMills как справочную и переписанную Reachability for Swift 3.1:

обновлено: Xcode 10.1 • Swift 4 или новее


Файл Reachability.swift

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

использование

Инициализируйте его в вашем методе AppDelegate.swift didFinishLaunchingWithOptions и обработайте все возможные ошибки:

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

И образец контроллера представления:

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

Пример проекта


2
Вам нужно удалить `== 0` из, if SCNetworkReachabilityGetFlags(…)поскольку xCode возвращает Bool в последней версии.
Мелвин

64
Это НЕ правильно, как упоминалось @NickM. НЕ РАБОТАЕТ ДЛЯ СОТОВЫХ СОЕДИНЕНИЙ . Не используйте это. Я удивлен, что у него так много голосов, может быть, это новинка с iOS 9 ... но я так не думаю.
Джордан Смит

1
Не работает на IOS9, нашел очень сложный способ - приложение в магазине ... так что, я думаю, даже если оно не на 100% точно и работает для некоторых, оно в лучшем случае противоречиво, так что тот, кто хочет рискнуть, может также захотеть сделать ставку на лошадь или песик, если им повезет.
Ник М

2
@NickM - это объясняет, почему так много голосов. @ Лео, возможно, было бы неплохо обновить свой ответ для iOS 9, чтобы спасти других людей, попавших в ту же ловушку. Я могу подтвердить, что это не работает (по крайней мере, в некоторых ситуациях) на iOS 9 ... однако переход на github.com/ashleymills/Reachability.swift работает нормально.
Джордан Смит

1
Да, я вижу, что это вылетело в ветке iOS10
Ace Green

225

Для Swift 3, Swift 4 (работа с сотовой связью и 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

    }
}

Использование:

if Reachability.isConnectedToNetwork(){
    print("Internet Connection Available!")
}else{
    print("Internet Connection not Available!")
}

3
Это решение + CoreTelephony (CTTelephonyNetworkInfo (). CurrentRadioAccessTechnology) является лучшим решением для получения текущего типа сети и без необходимости зависеть от сторонних библиотек.
Алехандро Хименес Агудо

3
Работает для сотовой связи и WiFi с Swift 3.1! Работает проверено на iPhone 6 и 7. Если сотовая связь выключена, я получаю ".. Соединение недоступно". Если я включаю режим полета, получаю то же самое "... не доступно". Если я отключаю сотовую связь и включаю Wi-Fi, я получаю «.. Соединение доступно», и, наконец, если я выключаю Wi-Fi и включаю сотовую связь, я получаю «... Соединение доступно». Обратите внимание, что мое сотовое соединение - LTE
Брайан,

1
Привет, это не работает на iOS 11, режим полета на физическом устройстве. Когда установлен режим полета, isReachable все еще верно ... есть идеи почему?
Лоуренс Тан

3
Это работает идеально для меня во всех сценариях. Это также проверено с iOS 12, работающим на iPhone 6.
r3dm4n

3
Это не работает, если я подключен к сети Wi-Fi без подключения к Интернету
Натан Баррето

58

Создайте новый файл Swift в своем проекте, назовите его Reachability.swift. Вырежьте и вставьте в него следующий код, чтобы создать свой класс.

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

    }
}

Вы можете проверить интернет-соединение в любом месте вашего проекта, используя этот код:

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

Если пользователь не подключен к Интернету, вы можете показать ему диалоговое окно с предупреждением, чтобы уведомить его.

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

Объяснение:

Мы создаем открытый класс многократного использования и метод, который можно использовать в любом месте проекта для проверки интернет-соединения. Нам требуется добавить основы и конфигурации системы.

В общедоступном классе Reachability метод isConnectedToNetwork() -> Bool { }вернет значение bool о подключении к Интернету. Мы используем цикл if для выполнения необходимых действий в случае. Надеюсь, этого достаточно. Ура!


4
Когда вы предлагаете решение, попробуйте немного его объяснить. Предоставление решения не важно, но важно, чтобы ваши читатели поняли решение и его концепцию.
Г.Абхисек

1
Я новичок в программировании iOS. Почему мы должны инициализировать структуру C для этой цели. В каких случаях мы можем использовать структуры C?
Г.Абхисек

1
я поставил это на "viewdidload" только для теста. Я открываю приложение и хорошо, у меня есть интернет, но когда я закрываю свой интернет, он продолжает показывать мне, что у меня есть интернет ... это постоянно? или я должен "призывать к действию" каждый раз?
Даниэль Арантес Ловерде

16
@AlvinGeorge это НЕ работает при подключении к сотовой сети. Это работает только при использовании Wi-Fi. Для всех остальных - вы не хотите использовать это в своем приложении! @ Элвин - могу ли я предложить вам обновить свой ответ или удалить его? С 19 голосами против это очень вводит в заблуждение других разработчиков, которые могут попасть в ту же ловушку.
Джордан Смит

@Jordan: этот метод использует стандартную структуру Apple для статуса сети. Это может измениться с новыми версиями iOS. Поэтому я рекомендую вам проверить и реализовать класс Reachability Эшели Милл. Я сделал реализацию без зависимостей и поделился ссылкой выше. Пожалуйста, посмотрите.
AG

56

Если кто-то уже использует Alamofire, тогда -

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

Использование:

if Connectivity.isConnectedToInternet {
     print("Connected")
 } else {
     print("No Internet")
}

1
из документации Alamofire:> Класс NetworkReachabilityManager прослушивает изменения достижимости хостов и адресов для сетевых интерфейсов WWAN и WiFi. > Достижимость может быть использована для определения исходной информации о причине сбоя сетевой операции или для повторной попытки сетевых запросов при установлении соединения. Его не следует использовать для предотвращения инициирования пользователем сетевого запроса, так как для установления достижимости может потребоваться первоначальный запрос.
fespinozacast

1
@fespinozacast хорошо, вы можете проверить код подключения к интернету в NetworkReachabilityManager.swift , что вполне нормально :)
Джек,

15

Я проверил реализацию класса Reachability Эшли Милл без Cocoa Pods / Dependancy Manager. Идея состоит в том, чтобы сделать зависимость Reachability свободной в проекте.

Xcode 7.2 - Swift 2.1

1) https://github.com/ashleymills/Reachability.swift . Скачать добавить класс Reachability в проект.

Примечание. При добавлении убедитесь, что установлен флажок «Копировать элементы при необходимости».

2) Создайте класс AppManager.swift. Этот класс будет обслуживать класс Public Model, куда будут добавляться публичные методы и данные, и его можно использовать в любом VC.

//  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) Создайте делегатский класс. Я использую метод делегата для уведомления о состоянии подключения.

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

4) Сделать родительский класс UIViewController (метод наследования). У родительского класса есть методы, которые доступны всем дочерним VC.

//  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) Запустите мониторинг интернет-соединения в реальном времени в AppDelegate.

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

6) Я добавил AppReference в Swift File Name для хранения постоянных значений перечисления.

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

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

}

7) На ViewController (например, вы хотите вызывать API, только если сеть доступна)

//  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() {
  }
}

Образец можно скачать @ https://github.com/alvinreuben/Reachability-Sample.

Обновлен до Swift 3.1 - https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3


На шаге 4 ... UIappViewController.swift, зачем нам этот класс !?
Learn2Code

UIappViewController.swift не работает с UICollectionViewController, поэтому, если у вас есть представление с UICollectionViewController, вы не можете наследовать UIappViewController !?
Learn2Code

12

Apple представила Network Framework в iOS12.

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

var path: NWPath? ноль Как мы инициализируем это свойство?
Витя Шурапов

@VityaShurapov При назначении пути вы попадаете в блок pathUpdateHandler.
Йогендра Сингх

Это выглядит странно, но я обнаружил (по крайней мере, на симуляторе), что если я выключу Wi-Fi моего ноутбука, затем включу, я получу обратный вызов, но он говорит «неудовлетворенный», и после этого обратный вызов никогда не будет вызываться.
Зайцман

Когда сотовые циклы включаются / выключаются, обработчик запускается только один раз для включения / выключения. Когда включается / выключается WiFi, я получаю 2 одинаковых триггера для включения / выключения (все свойства идентичны). Это почему?
Геохей

pathUpdateHandlerвведет сильную ссылку self, добавьте, [weak self]чтобы решить ее :)
Андреа де Марко

11

Используйте это для 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)
    }

}

Использование:

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

Или просто используйте это frameworkдля большегоUtilities : ссылка


@ DocAsh59 :) Добро пожаловать! Удачного кодирования!
Джамиль Хаснин Тамим

Я не понимаю использование этого. Компилятор показывает ошибку «Аргументы переданы в call, который не имеет аргументов».
Ролан Лариот

1
@RolandLariotte Вы просто класс в вашем проекте с именем - "InternetConnectionManager", а затем позвоните, где вы хотите!
Джамиль Хаснин Тамим

Работает отлично. Как вы думаете, этот код может быть более реактивным, используя Combine и возвращая AnyPublisher <Bool, Never>? Не могли бы вы написать это так?
Ролан Лариот

@RolandLariotte Да, может быть. Я напишу другой код позже. Спасибо и не забудьте поддержать! :)
Джамиль Хаснин Тамим

7

Просто понял это для себя.

Xcode: 7.3.1, iOS 9.3.3

Используя ashleymills / Reachability.swift в качестве Reachability.swift в моем проекте, я создал следующую функцию:

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

Просто позвоните hasConnectivity()туда, где вам нужно, чтобы проверить соединение. Это работает для Wi-Fi, а также сотовой связи.


Добавление ashleymills's Reachability.swift, чтобы людям не приходилось перемещаться между сайтами:

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

@ Xitcod13 Это будет работать с сетью 4G. При этом рекомендуется НЕ проверять предполетную проверку. Обработайте исключение, возникающее при попытке подключиться, вместо использования тестового примера Reachability.swift.
cmeadows


Reachabilty.swift имеет проблемы с Swift 3
Famic Tech

Хорошо работает со Swift 3, просто поменяйте let reachability: Reachability = try Reachability.reachabilityForInternetConnection()наlet reachability: Reachability = try Reachability()!
davidethell

7

Хотя это не дает прямого ответа на ваш вопрос, я хотел бы упомянуть, что Apple недавно провела эту беседу:

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

Около 09:55 он говорит о том, что вы делаете:

  1. Проверьте подключение
  2. Если соединение -> Сделай что-нибудь
  3. Если нет соединения -> сделать что-то еще (подождать? Повторить?)

Однако здесь есть несколько подводных камней:

  • Что если на шаге 2 написано, что у него есть соединение, а через 0,5 секунды - нет?
  • Что делать, если пользователь находится за прокси
  • И последнее, но не менее важное: что, если некоторые ответы здесь не могут определить правильность подключения? (Я уверен, что если вы быстро переключите свое соединение, зайдете в wi-fi и выключите его (просто усложните), оно почти никогда не сможет правильно определить, было у меня соединение или нет).
  • Цитата из видео: «Невозможно гарантировать, удастся ли будущая операция или нет»

Следующие пункты - некоторые лучшие практики согласно Apple:

Согласно сообщению, не должно быть никаких причин предварительно проверять, подключено ли у вас подключение к Интернету или нет, поскольку оно может быть неточным во время отправки запроса на сервер .


2

Я сделал свое собственное решение, используя NSTimer и Alamofire:

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

NSTimer используется как тайм-аут и использовался из-за ненадежных результатов с использованием тайм-аута Alamofire. Запрос должен быть направлен на надежный URL-адрес, например на ваш собственный сервер или сервер, на котором размещены службы, от которых вы зависите.

Когда таймер истекает, запрос отменяется и результаты возвращаются с использованием обработчика завершения.

Использование:

ConnectionHelper().isInternetConnected() { internetConnected in
    if internetConnected {
        // Connected
    } else {
        // Not connected
    }
}

1
Что делать, если сервер сайта не работает?
TechBee

Затем requestTimeout()будет вызван после истечения указанного времени ожидания
Марк Тикнер

Спасибо Марк! Ваш подход должен быть общим !!
TechBee

1
Каким образом? Сайт, который используется? Идея состоит в том, что используемый сайт - это тот, от которого зависит ваше приложение
Марк Тикнер,

Вероятно, не очень хорошая идея установить сетевое соединение и посмотреть, получит ли оно ответ или нет. Слишком много вопросов типа «что если»
GoodSp33d

2

Если вы используете Alamofire, вы можете сделать что-то вроде этого:

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

2

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

В любом методе используйте условие ниже

if currentReachabilityStatus == .notReachable {
    // Network Unavailable
 } else {
    // Network Available
 }

1

здесь мое решение для Swift 2.3 с lib ( Reachability.swift )

Зайдите в свой Podfileи добавьте:

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

Тогда в ваш terminal:

pod install

Затем создайте новый файл ReachabilityManagerи добавьте код ниже:

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
    }

}

Как это использовать:

зайдите в свой AppDelegate.swiftи добавьте код ниже:

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

Затем, когда вы хотите проверить, подключено ли устройство к Интернету, выполните:

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

1

Хотя он может не определять напрямую, подключен ли телефон к сети, самое простое (самое чистое?) Решение - это «пропинговать» Google или какой-либо другой сервер (что невозможно, если телефон не подключен к сети). ):

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
}

Если вы обеспокоены тем, что сервер может быть недоступен или может заблокировать ваш IP-адрес, вы всегда можете пропинговать несколько серверов одинаковым образом и узнать, доступен ли какой-либо из них. Или кто-то настроил выделенный сервер только для этой цели.


0

С помощью приведенного ниже кода вы можете проверить подключение к интернету как для сотовой сети, так и для Wi-Fi. язык - 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
    }
  }

}

0

Для Swift 3 я не мог использовать только достижимость от решений RAJAMOHAN-S, так как она возвращает «true», если есть WiFi, но нет Интернета. Таким образом, я реализовал вторую проверку с помощью класса URLSession и обработчика завершения.

Здесь весь класс.

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

И вы называете это так, например:

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

  // Do some action if there is Internet
}

0

Это моя версия. По сути, это не приносит ничего нового. Я связал это с UIDevice.

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

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

Теперь позвони

if Connectivity.isConnectedToInternet{
            call_your_methods_here()
        }else{
            show_alert_for_noInternet()
        }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.