如何使用SCNetworkReachability斯威夫特如何使用SCNetworkReachabi

2019-05-09 08:39发布

我想转换此代码段斯威夫特。 我挣扎上下车,由于一些困难地面。

- (BOOL) connectedToNetwork
{
    // Create zero addy
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    // Recover reachability flags
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;

    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);

    if (!didRetrieveFlags)
    {
        return NO;
    }

    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;

    return (isReachable && !needsConnection) ? YES : NO;
}

第一,我在的主要问题是如何定义与C结构的工作。 在第一行( struct sockaddr_in zeroAddress;上面的代码中,我认为他们是定义一个称为实例zeroAddress (?)从结构sockaddr_in中,我假设。 我想声明一个var是这样的。

var zeroAddress = sockaddr_in()

但我得到的错误缺少的参数变量“sin_len”呼叫这是可以理解的,因为结构发生了一些争论。 于是,我又试了一次。

var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)

正如预期的那样,我得到了自己的初始值中使用的一些其他错误变量 。 我的理解是错误的原因了。 在C语言中,他们首先声明实例,然后填写参数。 它不可能在斯威夫特据我所知。 所以我真的失去了在这一点上做什么。

我读了苹果的官方文档上与雨燕Ç的API进行交互,但它没有实例与结构的工作。

任何人都可以请帮我在这里? 我会很感激。

谢谢。


更新:感谢Martin我能闯过最初的问题。 但还是斯威夫特不是让我更容易。 我越来越多新的错误。

func connectedToNetwork() -> 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)

    var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>, UnsafePointer<zeroAddress>) // 'zeroAddress' is not a type
    var flags = SCNetworkReachabilityFlags()

    let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, UnsafeMutablePointer<flags>) // 'flags' is not a type
    defaultRouteReachability.dealloc(1) // 'SCNetworkReachabilityRef' does not have a member named 'dealloc'

    if didRetrieveFlags == false {
        return false
    }

    let isReachable: Bool = flags & kSCNetworkFlagsReachable // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'
    let needsConnection: Bool = flags & kSCNetworkFlagsConnectionRequired // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'

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

编辑1:好吧,我改变了这一行来此,

var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)

新的错误,我在这行得到的是“UnsafePointer”是无法转换为“CFAllocator”。 如何传递NULL斯威夫特?

此外,我改变了这一行,现在错误消失。

let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)

编辑2:我通过nil在此行后看到这个问题。 但是这个答案的答案矛盾在这里 。 它说,有没有相当于NULL斯威夫特。

var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)

无论如何,我得到一个新的错误说“sockaddr_in的”不等同于在上述行“SOCKADDR”。

Answer 1:

(这个答案一再延长由于雨燕语言的变化,这使得它有点混乱。我现在已经完全重写,并删除一切是指雨燕1.x中的旧的代码可以在编辑历史中找到,如果有人需要它。)

这是你会怎么做,在雨燕2.0(Xcode中7):

import SystemConfiguration

func connectedToNetwork() -> Bool {

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

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

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

    let isReachable = flags.contains(.Reachable)
    let needsConnection = flags.contains(.ConnectionRequired)

    return (isReachable && !needsConnection)
}

说明:

  • 如夫特1.2(6.3的Xcode),进口C的结构具有在夫特,初始化所有结构体的领域的零的默认初始值,所以套接字地址结构可以与被初始化

     var zeroAddress = sockaddr_in() 
  • sizeofValue()给出了该结构的大小,这必须被转换到UInt8sin_len

     zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress)) 
  • AF_INET是一个Int32 ,这必须被转换为正确的类型sin_family

     zeroAddress.sin_family = sa_family_t(AF_INET) 
  • withUnsafePointer(&zeroAddress) { ... }传递结构的地址给在那里它被用来作为参数为所述闭合SCNetworkReachabilityCreateWithAddress() 所述UnsafePointer($0)需要转换,因为函数需要一个指针sockaddr ,不sockaddr_in

  • 从返回的值withUnsafePointer()是从返回值SCNetworkReachabilityCreateWithAddress()并具有类型SCNetworkReachability? ,即它是一个可选的。 该guard let语句(斯威夫特2.0中的新功能)分配展开值到defaultRouteReachability如果不是变量nil 。 否则, else块被执行,函数返回。

  • 作为夫特2, SCNetworkReachabilityCreateWithAddress()返回一个管理对象。 你不必明确地释放它。
  • 作为夫特2, SCNetworkReachabilityFlags符合OptionSetType其具有一组类似的接口。 您创建一个空的标志变

     var flags : SCNetworkReachabilityFlags = [] 

    并检查与标志

     let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired) 
  • 的第二个参数SCNetworkReachabilityGetFlags具有类型UnsafeMutablePointer<SCNetworkReachabilityFlags>这意味着你必须通过可变标志的地址

还要注意的是注册通知回调是尽可能夫特2,比较与来自夫特Ç的API工作和夫特2 - UnsafeMutablePointer <空隙>到对象 。


更新斯威夫特3/4:

不安全的指针不能简单地被转换成不同类型的指针了(见- SE-0107 UnsafeRawPointer API )。 在这里,更新后的代码:

import SystemConfiguration

func connectedToNetwork() -> Bool {

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

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

    let isReachable = flags.contains(.reachable)
    let needsConnection = flags.contains(.connectionRequired)

    return (isReachable && !needsConnection)
}


Answer 2:

斯威夫特3,IPv4的IPv6的

根据马丁的r答案:

import SystemConfiguration

func isConnectedToNetwork() -> Bool {
    guard let flags = getFlags() else { return false }
    let isReachable = flags.contains(.reachable)
    let needsConnection = flags.contains(.connectionRequired)
    return (isReachable && !needsConnection)
}

func getFlags() -> SCNetworkReachabilityFlags? {
    guard let reachability = ipv4Reachability() ?? ipv6Reachability() else {
        return nil
    }
    var flags = SCNetworkReachabilityFlags()
    if !SCNetworkReachabilityGetFlags(reachability, &flags) {
        return nil
    }
    return flags
}

func ipv6Reachability() -> SCNetworkReachability? {
    var zeroAddress = sockaddr_in6()
    zeroAddress.sin6_len = UInt8(MemoryLayout<sockaddr_in>.size)
    zeroAddress.sin6_family = sa_family_t(AF_INET6)

    return withUnsafePointer(to: &zeroAddress, {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
    })
}

func ipv4Reachability() -> SCNetworkReachability? {
    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
    zeroAddress.sin_family = sa_family_t(AF_INET)

    return withUnsafePointer(to: &zeroAddress, {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
    })
}


Answer 3:

这有没有关系斯威夫特,但最好的解决办法是不使用的可达性来确定网络是否在线。 只是让你的连接,如果失败处理错误。 建立连接可以在次火起来的休眠离线收音机。

可达性的一个有效的用途是用它来通知你当网络的过渡,从离线到在线。 在这一点上你应该重新尝试失败的连接。



Answer 4:

最好的解决办法是使用ReachabilitySwift 类 ,写在Swift 2 ,并使用SCNetworkReachabilityRef

简单易用:

let reachability = Reachability.reachabilityForInternetConnection()

reachability?.whenReachable = { reachability in
    // keep in mind this is called on a background thread
    // and if you are updating the UI it needs to happen
    // on the main thread, like this:
    dispatch_async(dispatch_get_main_queue()) {
        if reachability.isReachableViaWiFi() {
            print("Reachable via WiFi")
        } else {
            print("Reachable via Cellular")
        }
    }
}
reachability?.whenUnreachable = { reachability in
    // keep in mind this is called on a background thread
    // and if you are updating the UI it needs to happen
    // on the main thread, like this:
    dispatch_async(dispatch_get_main_queue()) {
        print("Not reachable")
    }
}

reachability?.startNotifier()

工作就像一个魅力。

请享用



Answer 5:

更新juanjo的回答创建单个实例

import Foundation
import SystemConfiguration

final class Reachability {

    private init () {}
    class var shared: Reachability {
        struct Static {
            static let instance: Reachability = Reachability()
        }
        return Static.instance
    }

    func isConnectedToNetwork() -> Bool {
        guard let flags = getFlags() else { return false }
        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)
        return (isReachable && !needsConnection)
    }

    private func getFlags() -> SCNetworkReachabilityFlags? {
        guard let reachability = ipv4Reachability() ?? ipv6Reachability() else {
            return nil
        }
        var flags = SCNetworkReachabilityFlags()
        if !SCNetworkReachabilityGetFlags(reachability, &flags) {
            return nil
        }
        return flags
    }

    private func ipv6Reachability() -> SCNetworkReachability? {
        var zeroAddress = sockaddr_in6()
        zeroAddress.sin6_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin6_family = sa_family_t(AF_INET6)

        return withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        })
    }
    private func ipv4Reachability() -> SCNetworkReachability? {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        return withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        })
    }
}

用法

if Reachability.shared.isConnectedToNetwork(){

}


Answer 6:

这是斯威夫特4.0

我使用这个框架https://github.com/ashleymills/Reachability.swift
并安装波德..
AppDelegate中

var window: UIWindow?
var reachability = InternetReachability()!
var reachabilityViewController : UIViewController? = nil

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    reachabilityChecking()
    return true
}

extension AppDelegate {

func reachabilityChecking() {    
    reachability.whenReachable = { reachability in
        DispatchQueue.main.async {
            print("Internet is OK!")
            if reachability.connection != .none && self.reachabilityViewController != nil {

            }
        }
    }
    reachability.whenUnreachable = { _ in
        DispatchQueue.main.async {
            print("Internet connection FAILED!")
            let storyboard = UIStoryboard(name: "Reachability", bundle: Bundle.main)
            self.reachabilityViewController = storyboard.instantiateViewController(withIdentifier: "ReachabilityViewController")
            let rootVC = self.window?.rootViewController
            rootVC?.present(self.reachabilityViewController!, animated: true, completion: nil)
        }
    }
    do {
        try reachability.startNotifier()
    } catch {
        print("Could not start notifier")
    }
}
}

如果互联网不存在屏幕上会出现



文章来源: How to use SCNetworkReachability in Swift