当前位置: 首页 > 面试题库 >

如何在Swift中使用SCNetworkReachability

轩辕亮
2023-03-14
问题内容

我正在尝试将此代码段转换为Swift。由于某些困难,我正在努力下车。

- (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从struct
sockaddr_in(?)调用的实例。我试图声明var这样的。

var zeroAddress = sockaddr_in()

但是我 调用 得到了 参数’sin_len’ 的错误 Missing参数 错误
这是可以理解的,因为该结构需要多个参数。所以我再次尝试。

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

不出所料,我 在自己的初始值中使用 了其他错误 变量
。我也了解该错误的原因。在C语言中,他们首先声明实例,然后填充参数。据我所知,这在Swift中是不可能的。因此,我现在真的迷失了该做什么。

我阅读了Apple的有关在Swift中与C
API交互的官方文档,但其中没有使用结构的示例。

有人可以在这里帮我吗?我真的很感激。

谢谢。

更新: 感谢马丁,我得以解决最初的问题。但是Swift仍然不能使我更轻松。我收到多个新错误。

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’ 。如何通过NULLSwift?

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

let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)

编辑2:nil看到此问题后,我通过了这一行。但是那个答案与这里的答案相矛盾。它说NULL在Swift中没有等效的功能。

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

无论如何,我收到一个新错误,说 “ sockaddr_in”与 上一行中的 “ sockaddr”并不相同


问题答案:

(此答案由于Swift语言的更改而反复扩展,这使它有点混乱。我现在将其重写并删除了所有与Swift
1.x相关的内容。如果有人需要,可以在编辑历史记录中找到较旧的代码。它。)

这就是您在 Swift 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)
}

说明:

  • 从Swift 1.2(Xcode 6.3)开始,导入的C结构在Swift中具有默认的初始化程序,该初始化程序将该结构的所有字段初始化为零,因此可以使用以下方式初始化套接字地址结构:

    var zeroAddress = sockaddr_in()
    
  • sizeofValue()给出此结构的大小,必须将其转换UInt8sin_len

    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    
  • AF_INETInt32,必须将其转换为以下类型的正确类型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执行该块,然后函数返回。

  • 从Swift 2开始,SCNetworkReachabilityCreateWithAddress()返回一个托管对象。您不必显式释放它。

  • 从Swift 2开始,SCNetworkReachabilityFlags符合的 OptionSetType具有类似set的界面。您使用创建一个空标志变量
    var flags : SCNetworkReachabilityFlags = []
    

并检查标志

    let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
  • 的第二个参数SCNetworkReachabilityGetFlags具有type UnsafeMutablePointer<SCNetworkReachabilityFlags>,这意味着您必须传递flags变量的 地址

另请注意,从Swift2开始,可以注册一个通告程序回调,将使用Swift和Swift2中的C API与Swift 2-UnsafeMutablePointer
<Void>与object进行比较。

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


 类似资料:
  • 问题内容: 我想在我的Swift应用程序中绘制折线。 SWIFT代码 错误: 我找不到解决方案。 问题答案: 首先 ,必须创建一个。 自iOS 7起已弃用,尽管您仍可以在Objective-C中使用它,但在Swift中不支持它。 其次 ,您必须在委托方法中创建并返回一个(不要将其传递给)。 在方法中,传递对象(而不是or )。 以解释传递给哪个对象与返回的对象之间的区别。) 因此,在该方法中,删除

  • 问题内容: 有没有人设法使此功能在Swift中工作? 苹果文档:https : //developer.apple.com/library/prerelease/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/func/CGEventTapCreate 以下是CGEventTapC

  • 问题内容: 在Objective-C中,我们使用以下代码为视图设置RGB颜色代码: 如何在Swift中使用它? 问题答案: 这是该函数的Swift版本(用于获取值的UIColor表示形式):

  • 问题内容: 有人能帮我吗?我找不到完整的语法示例。 问题答案: 不清楚您要问 的 是什么 ,但我注意到您在代码中有几个错误: 您应该创建使用 返回,因此无需将其包装在内部(也称为实例化新对象)。 完成处理程序是一个闭包,下面是创建该特定闭包的方法: } 这是更新的代码:

  • 问题内容: 如何在Swift中使用UserDefaults保存/检索字符串,布尔值和其他数据? 问题答案: 参考:NSUserdefault objectTypes 商店 取回 去掉 删除所有键 Swift 2及以下 商店 取回 去掉 寄存器 registerDefaults:将registrationDictionary添加到每个搜索列表的最后一项。这意味着在NSUserDefaults在所有其

  • 问题内容: 我阅读了Xcode 6的新增功能。本文介绍了有关Xcode 6的一些新功能,并说: 命令行 Xcode的调试器包括Swift语言的交互式版本,称为REPL(Read-Eval-Print- Loop)。使用Swift语法来评估正在运行的应用程序并与之交互,或者在类似脚本的环境中编写新代码。REPL可从Xcode控制台的LLDB或Terminal中获得。 我想知道如何获得REPL? 问题