swift - 检查当前 swift 4.1 中所有页面的互联网连接

标签 swift xcode swift4.1

只有一个viewController。我应该在 didFinishLaunchingWithOptions 范围内的 AppDelegate.swift 文件中写什么?

第 1 部分

AppDelegate.swift

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

    // WHAT SHOULD I WRITE IN THIS SCOOPE ?

    return true
}

第 2 部分

viewController.swift

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}
}

第 3 部分

ReachabilityHandler.swift

import Foundation
import UIKit
class ReachabilityHandler {
    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(statusChanged), name: .flagsChanged, object: Network.reachability)
    }

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func statusChanged(_ notification: NSNotification) {
    guard
        let isReachable = Network.reachability?.isReachable,
        let visibleViewController = UIApplication.shared.visibleViewController
        else { return }


    if false == isReachable {
        let alert = UIAlertController(title: "Title", message: "Offline", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
        visibleViewController.present(alert, animated: true, completion: nil)
    }
}
}

第 4 部分

extension_UIApplication.swift

import Foundation
import UIKit

extension UIApplication {
    var visibleViewController: UIViewController? {

    guard let rootViewController = keyWindow?.rootViewController else {
        return nil
    }

    return getVisibleViewController(rootViewController)
}

private func getVisibleViewController(_ rootViewController: UIViewController) -> UIViewController? {

    if let presentedViewController = rootViewController.presentedViewController {
        return getVisibleViewController(presentedViewController)
    }

    if let navigationController = rootViewController as? UINavigationController {
        return navigationController.visibleViewController
    }

    if let tabBarController = rootViewController as? UITabBarController {
        return tabBarController.selectedViewController
    }

    return rootViewController
}
}

第 5 部分

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
    }
    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
    }
    var status: Network.Status {
        return  !isConnectedToNetwork ? .unreachable :
            isReachableViaWiFi    ? .wifi :
            isRunningOnDevice     ? .wwan : .unreachable
    }
    var isRunningOnDevice: Bool = {
        #if (arch(i386) || arch(x86_64)) && os(iOS)
        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, CustomStringConvertible {
        case unreachable, wifi, wwan
        var description: String { return rawValue }
    }
    enum Error: Swift.Error {
        case failedToSetCallout
        case failedToSetDispatchQueue
        case failedToCreateWith(String)
        case failedToInitializeWith(sockaddr_in)
    }
}

最佳答案

这是个好问题。对于您的问题,我建议您使用单例模式,这是一个更好的解决方案。因为我们在整个应用程序的任何地方使用。 你可以从一篇很好的文章中阅读这个例子。 https://medium.com/@sauvik_dolui/network-status-monitoring-on-ios-part-1-9a22276933dc

关于swift - 检查当前 swift 4.1 中所有页面的互联网连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50525946/

相关文章:

swift - 如何使用带有元组模式匹配的 Swift switch 语句来表达 "not equal to"

xcode - 找不到选项的目录 - 升级 Swift 2.0

ios - 单击 UICollectionViewCell 时如何转换到新 Controller (以编程方式)

core-image - Swift 4.1 无法获得此 NSImage 的位图表示

ios - 使用@testable 时“模块未编译用于测试”

ios - AWS S3 : file not uploading in folder in ios

ios - 无法为具有 subview Controller 的两个容器 UIView 的位置更改设置动画

objective-c - 将 .plist 文件与 iCloud 同步

ios - Xcode 10 中 map 功能的变化