Kiểm tra kết nối internet với Swift


251

Khi tôi cố kiểm tra kết nối internet trên iPhone, tôi gặp phải một loạt lỗi. Bất cứ ai có thể giúp tôi khắc phục điều này?

Mật mã:

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
}

}

Các lỗi với mã:

Lỗi

Nếu không thể đọc được, lỗi 1 cho biết:

'Int' không thể chuyển đổi thành 'SCNetworkReachabilityFlags'

Lỗi 2 & 3:

Không thể tìm thấy quá tải cho 'init' chấp nhận các đối số được cung cấp


1
Mã này trông giống như những gì tôi đã đề xuất ở đây: stackoverflow.com/a/25623647/1187415 , vì vậy tôi đã cập nhật mã đó cho Swift 2.
Martin R

2
Tôi đã có một triển khai Khả năng tiếp cận Swift 2 hoạt động đầy đủ tại đây, github.com/ashleymills/Reachability.swift - Hãy sử dụng nó làm tài liệu tham khảo.
Ashley Mills

1
stackoverflow.com/a/25623647/1187415 Hiện đã được cập nhật cho Swift 3, Xcode 8 beta 6.
Martin R

1
Apple cung cấp một mẫu Swift chính thức và bạn có thể lấy nó trên Cốc Cốc . Nó tương thích với bất kỳ dự án Swift nào.
Cœur

Câu trả lời:


368

Để giải quyết vấn đề 4G được đề cập trong các nhận xét, tôi đã sử dụng triển khai khả năng tiếp cận @AshleyMills làm tài liệu tham khảo và viết lại Khả năng tiếp cận cho Swift 3.1:

đã cập nhật: Xcode 10.1 • Swift 4 trở lên


Tập tin 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)
    }
}

Sử dụng

Khởi tạo nó trong phương thức AppDelegate.swift didFinishLaunchingWithOptions của bạn và xử lý mọi lỗi có thể xảy ra:

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

Và một mẫu điều khiển xem:

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

Dự án mẫu


2
Bạn cần xóa `== 0` khỏi if SCNetworkReachabilityGetFlags(…)xCode trả về Bool trong phiên bản mới nhất.
Melvin

64
Điều này KHÔNG chính xác như @NickM đã đề cập. SILL KHÔNG LÀM VIỆC CHO KẾT NỐI BÁN HÀNG . Đừng dùng cái này. Tôi ngạc nhiên khi nó có rất nhiều lượt bình chọn, có thể đây là bản mới của iOS 9 ... nhưng tôi không nghĩ vậy.
Jordan Smith

1
Không hoạt động trên IOS9, phát hiện ra một cách rất khó khăn - ứng dụng trong cửa hàng ... vì vậy tôi đoán ngay cả khi nó không chính xác 100% và nó hoạt động với một số người, nó không nhất quán, vì vậy bất cứ ai muốn có cơ hội cũng có thể muốn đặt cược vào một số con ngựa hoặc chó con nếu họ cảm thấy may mắn.
Nick M

2
@NickM - điều đó giải thích tại sao rất nhiều phiếu bầu. @ Leo có thể là một ý tưởng tốt để cập nhật câu trả lời của bạn cho iOS 9, để cứu người khác vấp vào cùng một cái bẫy. Tôi có thể xác nhận nó không hoạt động (ít nhất là trong một số tình huống) trên iOS 9 ... thay đổi thành github.com/ashleymills/Reachability.swift hoạt động tốt.
Jordan Smith

1
Phải, tôi thấy nó đã được đưa ra trong chi nhánh iOS10
Ace Green

224

Đối với Swift 3, Swift 4 (hoạt động với di động và 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

    }
}

Sử dụng:

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

3
Giải pháp này + CoreTelephony (CTTelephonyNetworkInfo (). CurrentRadioAccessT Technology) là giải pháp tốt nhất để có được loại mạng hiện tại và không cần phụ thuộc vào libs của bên thứ ba.
Alejandro Jiménez Agudo

3
Hoạt động cho Cellular và WiFi với swift 3.1! Hoạt động được thử nghiệm trên iPhone 6 và 7. Nếu Cellular Off tôi nhận được "..Kết nối không khả dụng". Nếu tôi bật chế độ máy bay, hãy nhận "... không khả dụng". Nếu tôi tắt di động và bật wifi, tôi nhận được ".. Kết nối khả dụng" và cuối cùng nếu tôi tắt wifi và bật Cellular, tôi sẽ nhận được ".. Kết nối khả dụng". Lưu ý kết nối di động của tôi là LTE
Brian

1
Xin chào, điều này không hoạt động trên iOS 11, chế độ máy bay trên thiết bị vật lý. Khi được đặt ở chế độ máy bay, isReachable vẫn đúng ... mọi ý kiến ​​tại sao?
Lawrence Tan

3
Điều này đang làm việc hoàn hảo cho tôi trong tất cả các kịch bản. Nó cũng đã được thử nghiệm với iOS 12 chạy trên iPhone 6.
r3dm4n

3
Điều này không hoạt động nếu tôi kết nối với mạng wifi mà không có kết nối internet
Nathan Barreto

58

Tạo một tệp Swift mới trong dự án của bạn, đặt tên cho nó Reachability.swift. Cắt và dán đoạn mã sau vào nó để tạo lớp của bạn.

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

    }
}

Bạn có thể kiểm tra kết nối internet ở bất cứ đâu trong dự án của bạn bằng mã này:

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

Nếu người dùng không được kết nối với internet, bạn có thể muốn hiển thị cho họ hộp thoại cảnh báo để thông báo cho họ.

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

Giải trình:

Chúng tôi đang tạo ra một lớp công khai có thể tái sử dụng và một phương pháp có thể được sử dụng ở bất cứ đâu trong dự án để kiểm tra kết nối internet. Chúng tôi yêu cầu thêm khung cấu hình Foundation và System.

Trong Khả năng tiếp cận lớp công khai, phương thức isConnectedToNetwork() -> Bool { }sẽ trả về giá trị bool về kết nối internet. Chúng tôi sử dụng một vòng lặp if để thực hiện các hành động cần thiết trong trường hợp. Tôi hy vọng điều này là đủ. Chúc mừng!


4
Khi bạn đang đưa ra một giải pháp, hãy cố gắng giải thích nó một chút. Đưa ra giải pháp không quan trọng, nhưng làm cho độc giả của bạn hiểu giải pháp & khái niệm của nó quan trọng hơn.
G.Abhisek

1
Tôi mới làm quen với lập trình iOS. Tại sao chúng ta cần khởi tạo một cấu trúc C cho mục đích này. Trong trường hợp nào chúng ta có thể sử dụng cấu trúc C?
G.Abhisek

1
tôi đặt cái này vào "viewdidload" chỉ để thử nghiệm. Tôi mở ứng dụng và OK, có internet, nhưng khi tôi tắt internet, nó tiếp tục cho tôi thấy tôi có internet ... điều này có tồn tại không? hoặc tôi phải "gọi hành động" mọi lúc?
Daniel Arantes Loverde

16
@AlvinGeorge điều này KHÔNG hoạt động khi được kết nối với mạng di động. Điều này chỉ hoạt động khi sử dụng wifi. Cho bất cứ ai khác - bạn không muốn sử dụng điều này trong ứng dụng của bạn! @ Alvin - Tôi có thể đề nghị bạn cập nhật câu trả lời của mình hoặc xóa nó không? Với 19 phiếu bầu, rất dễ gây hiểu lầm cho các nhà phát triển khác có thể rơi vào cùng một cái bẫy.
Jordan Smith

@Jordan: Phương pháp này đang sử dụng khung apple mặc định cho trạng thái mạng. Nó có thể thay đổi với các phiên bản iOS mới. Vì vậy, tôi khuyên bạn nên kiểm tra và triển khai lớp Khả năng tiếp cận của Ashely Mill. Tôi đã thực hiện một phụ thuộc miễn phí thực hiện và chia sẻ liên kết ở trên. Xin hãy xem.
AG

56

Nếu ai đó đã sử dụng Alamofire thì -

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

Sử dụng:

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

1
từ tài liệu của Alamofire:> Lớp NetworkReachabilityManager lắng nghe những thay đổi về khả năng tiếp cận của máy chủ và địa chỉ cho cả giao diện mạng WWAN và WiFi. > Khả năng tiếp cận có thể được sử dụng để xác định thông tin cơ bản về lý do tại sao hoạt động mạng không thành công hoặc thử lại các yêu cầu mạng khi kết nối được thiết lập. Không nên sử dụng nó để ngăn người dùng bắt đầu yêu cầu mạng, vì có thể yêu cầu ban đầu có thể được yêu cầu để thiết lập khả năng tiếp cận.
fespinozacast

1
@fespinozacast, bạn có thể kiểm tra mã kết nối internet trong NetworkReachabilityManager.swift , điều này hoàn toàn tốt :)
Jack

15

Tôi đã kiểm tra việc triển khai lớp Khả năng tiếp cận của Ashley Mill mà không có Trình quản lý / phụ thuộc ca cao. Ý tưởng là làm cho sự phụ thuộc Reachability miễn phí trong dự án.

Xcode 7.2 - Swift 2.1

1) https://github.com/ashleymills/Reachability.swift . Tải về thêm lớp Khả năng tiếp cận vào dự án.

Lưu ý: Trong khi thêm, vui lòng đảm bảo 'sao chép các mục nếu cần' được đánh dấu.

2) Tạo một lớp AppManager.swift. Lớp này sẽ phục vụ như lớp Mô hình công cộng nơi các phương thức & dữ liệu công khai sẽ được thêm vào và có thể được sử dụng trong bất kỳ VC nào.

//  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) Lập một lớp đại biểu. Tôi sử dụng phương pháp ủy nhiệm để thông báo trạng thái kết nối.

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

4) Tạo lớp Parent của UIViewControll (Phương thức kế thừa). Lớp cha có các phương thức có thể truy cập được tất cả các VC con.

//  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) Bắt đầu theo dõi kết nối Internet thời gian thực trong AppDelegate.

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

6) Tôi đã thêm AppReference tên tệp Swift để lưu trữ giá trị enum không đổi.

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

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

}

7) Trên ViewContoder (ví dụ: Bạn chỉ muốn gọi API nếu mạng khả dụng)

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

Có thể tải xuống mẫu @ https://github.com/alvinreuben/Reachability-Sample

Được nâng cấp lên Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3


Ở Bước 4 ... UIappViewControll.swift, tại sao chúng ta cần lớp này!?
Tìm hiểu2Code

UIappViewControll.swift không hoạt động với UICollectionViewControll, vì vậy nếu bạn có Chế độ xem là của UICollectionViewContaptor, bạn không thể kế thừa UIappViewControll!?
Tìm hiểu2Code

12

Apple đã giới thiệu Network Framework trong 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
   }
 }

đường dẫn var: NWPath? là con số không Làm thế nào để chúng tôi khởi tạo tài sản này?
Vitya Shurapov

@VityaShurapov Bằng cách chỉ định đường dẫn bạn đang nhận trong khối pathUpdateHandler.
Yogendra Singh

Điều này có vẻ lạ mắt nhưng tôi thấy (ít nhất là trên trình giả lập) rằng nếu tôi tắt wifi máy tính xách tay của mình, tôi sẽ nhận được một cuộc gọi lại nhưng nó nói 'không hài lòng', và sau đó cuộc gọi lại không bao giờ được gọi.
zaitsman

Khi bật / tắt chu trình di động, trình xử lý chỉ kích hoạt một lần cho bật / tắt. Khi bật / tắt WiFi, tôi nhận được 2 kích hoạt giống nhau cho bật / tắt (tất cả các thuộc tính đều giống hệt nhau). Tại sao vậy?
geohei

pathUpdateHandlersẽ giới thiệu một tài liệu tham khảo mạnh mẽ với self, thêm [weak self]vào để giải quyết nó :)
Andrea de Marco

11

Sử dụng cái này cho 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)
    }

}

Sử dụng:

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

Hoặc chỉ sử dụng cái này frameworkđể biết thêmUtilities : Liên kết


@ DocAsh59 :) Chào mừng bạn! Chúc mừng mã hóa!
Jamil Hasnine Tamim

Tôi không hiểu cách sử dụng nó. Trình biên dịch hiển thị lỗi "Đối số được truyền cho cuộc gọi không có đối số".
Roland Lariotte

1
@RolandLariotte Bạn chỉ cần lớp trong dự án của bạn có tên - "InternetConnectionManager", và sau đó gọi từ nơi bạn muốn!
Jamil Hasnine Tamim

Hoạt động hoàn hảo. Bạn có nghĩ rằng mã này có thể phản ứng mạnh hơn bằng cách sử dụng Kết hợp và trả về AnyPublisher <Bool, Never> không? Bạn có thể viết nó theo cách này?
Roland Lariotte

@RolandLariotte Vâng, có thể. Tôi sẽ viết một mã khác sau. Cảm ơn và đừng quên hỗ trợ! :)
Jamil Hasnine Tamim

7

Chỉ cần tìm ra điều này cho bản thân mình.

Xcode: 7.3.1, iOS 9.3.3

Sử dụng ashleymills / Reachability.swift làm Reachability.swift trong dự án của tôi, tôi đã tạo ra chức năng sau:

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

Chỉ cần gọi bất cứ hasConnectivity()nơi nào bạn cần để kiểm tra kết nối. Điều này hoạt động cho Wifi cũng như di động.


Thêm Reachability.swift của ashleymills để mọi người không phải di chuyển giữa các trang web:

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 Điều này sẽ hoạt động với Mạng 4G. Điều đó được nói rằng không nên thử nghiệm preflight. Xử lý ngoại lệ được ném trong nỗ lực kết nối của bạn thay vì sử dụng trường hợp kiểm tra Reachability.swift.
cmeadows


Reachabilty.swift có vấn đề với Swift 3
Famic Tech

Hoạt động tốt với Swift 3, chỉ cần đổi let reachability: Reachability = try Reachability.reachabilityForInternetConnection()thànhlet reachability: Reachability = try Reachability()!
davidethell

7

Mặc dù nó không trả lời trực tiếp câu hỏi của bạn, nhưng tôi muốn đề cập đến Apple gần đây đã có cuộc nói chuyện này:

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

Vào khoảng 09:55 anh ấy nói về việc làm những thứ bạn đang hỏi về:

  1. Kiểm tra kết nối
  2. Nếu kết nối -> Làm gì đó
  3. Nếu không có kết nối -> Làm gì khác (chờ? Thử lại?)

Tuy nhiên, điều này có một vài cạm bẫy:

  • Điều gì sẽ xảy ra nếu ở bước 2 nó nói nó có kết nối, nhưng 0,5 giây sau anh ta không có?
  • Điều gì xảy ra nếu người dùng đứng sau một proxy
  • Cuối cùng nhưng không kém phần quan trọng, nếu một số câu trả lời ở đây không thể xác định được kết nối thì sao? (Tôi chắc chắn rằng nếu bạn nhanh chóng chuyển đổi kết nối của mình, hãy truy cập wi-fi và tắt nó đi (chỉ làm cho nó phức tạp), gần như không bao giờ có thể xác định chính xác bất cứ khi nào tôi có kết nối hay không).
  • Trích dẫn từ video: "Không có cách nào để đảm bảo liệu một hoạt động trong tương lai sẽ thành công hay không"

Những điểm sau đây là một số thực tiễn tốt nhất theo Apple:

Theo cuộc nói chuyện, không nên có bất kỳ lý do nào để kiểm tra trước bất cứ khi nào bạn có kết nối internet hay không, vì nó có thể không chính xác tại thời điểm bạn gửi yêu cầu của mình đến máy chủ .


2

Tôi đã thực hiện giải pháp của riêng mình bằng NSTimer và 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 được sử dụng làm thời gian chờ và được sử dụng do kết quả không đáng tin cậy khi sử dụng thời gian chờ của Alamofire. Yêu cầu phải được gửi tới một URL mà bạn tin tưởng là đáng tin cậy, chẳng hạn như máy chủ của riêng bạn hoặc máy chủ lưu trữ các dịch vụ mà bạn phụ thuộc.

Khi hết giờ, yêu cầu bị hủy và kết quả được trả về bằng trình xử lý hoàn thành.

Sử dụng:

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

1
Nếu máy chủ trang web ngừng hoạt động thì sao?
TechBee 2/2/2016

Sau đó requestTimeout()sẽ được gọi sau khi hết thời gian quy định
Mark Tickner

Cảm ơn Mark! Cách tiếp cận của bạn nên chung chung !!
TechBee 2/2/2016

1
Bằng cách nào? Các trang web được sử dụng? Ý tưởng là trang web được sử dụng là trang mà ứng dụng của bạn phụ thuộc vào
Mark Tickner

Có lẽ không phải là một ý tưởng tốt để thực hiện kết nối mạng và xem liệu nó có trở lại với một phản hồi hay không. Đơn giản là có quá nhiều điều nếu câu hỏi
GoodSp33d

2

Nếu bạn đang sử dụng Alamofire, bạn có thể làm một cái gì đó như thế này:

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

1

đây là giải pháp của tôi cho swift 2.3 với lib ( Reachability.swift )

Đi vào của bạn Podfilevà thêm:

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

Sau đó vào terminal:

pod install

Sau đó tạo một tệp mới ReachabilityManagervà thêm mã dưới đây:

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
    }

}

Cách sử dụng:

đi vào của bạn AppDelegate.swiftvà thêm mã dưới đây:

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

Sau đó, khi bạn muốn kiểm tra xem thiết bị có được kết nối với internet không:

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

1

Mặc dù có thể không trực tiếp xác định liệu điện thoại có được kết nối với mạng hay không, nhưng giải pháp đơn giản nhất (sạch nhất?) Sẽ là 'ping' Google hoặc một số máy chủ khác, (không thể thực hiện được trừ khi điện thoại được kết nối với mạng ):

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
}

Nếu bạn lo ngại rằng máy chủ có thể ngừng hoạt động hoặc có thể chặn IP của bạn, bạn luôn có thể ping nhiều máy chủ theo cách tương tự và trả lại cho dù bất kỳ máy chủ nào có thể truy cập được. Hoặc có ai đó thiết lập một máy chủ chuyên dụng chỉ cho mục đích này.


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

Trong mọi phương pháp sử dụng điều kiện dưới đây

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

0

Với sự trợ giúp của mã dưới đây, bạn có thể kiểm tra Kết nối internet cho cả mạng di động cũng như wifi. ngôn ngữ - 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

Đối với swift 3, tôi không thể chỉ sử dụng khả năng tiếp cận từ các giải pháp RAJAMOHAN-S vì nó trả về "true" nếu có WiFi nhưng không có Internet. Vì vậy, tôi đã triển khai xác nhận thứ hai thông qua lớp URLSession và trình xử lý hoàn thành.

Đây là cả lớp.

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

Và bạn gọi nó như thế này, ví dụ:

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

  // Do some action if there is Internet
}

0

Đây là phiên bản của tôi. Về cơ bản, nó không mang lại điều gì mới. Tôi ràng buộc nó với 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
        }
    }

Bây giờ gọi nó

if Connectivity.isConnectedToInternet{
            call_your_methods_here()
        }else{
            show_alert_for_noInternet()
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.