我正在尝试将此代码段转换为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这样的。
struct sockaddr_in zeroAddress;
zeroAddress
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?
NULL
我也改变了这一行,错误现在消失了。
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
编辑2:nil看到此问题后,我通过了这一行。但是那个答案与这里的答案相矛盾。它说NULL在Swift中没有等效的功能。
nil
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中具有默认的初始化程序,该初始化程序将该结构的所有字段初始化为零,因此可以使用以下方式初始化套接字地址结构:
sizeofValue()给出此结构的大小,必须将其转换UInt8为sin_len:
sizeofValue()
UInt8
sin_len
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
AF_INET是Int32,必须将其转换为以下类型的正确类型sin_family:
AF_INET
Int32
sin_family
zeroAddress.sin_family = sa_family_t(AF_INET)
withUnsafePointer(&zeroAddress) { ... }将结构的地址传递到闭包,在闭包处作为实参 SCNetworkReachabilityCreateWithAddress()。该UnsafePointer($0) 转换是必要的,因为该功能需要一个指针 sockaddr,而不是sockaddr_in。
withUnsafePointer(&zeroAddress) { ... }
SCNetworkReachabilityCreateWithAddress()
UnsafePointer($0)
sockaddr
sockaddr_in
从中withUnsafePointer()返回的值是从的返回值SCNetworkReachabilityCreateWithAddress(),其类型为SCNetworkReachability?,即它是可选的。的guard let声明(在夫特2.0新功能)分配展开值到defaultRouteReachability如果不是可变nil。否则else执行该块,然后函数返回。
withUnsafePointer()
SCNetworkReachability?
guard let
defaultRouteReachability
else
从Swift 2开始,SCNetworkReachabilityCreateWithAddress()返回一个托管对象。您不必显式释放它。
SCNetworkReachabilityFlags
OptionSetType
var flags : SCNetworkReachabilityFlags = []
并检查标志
let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired)
SCNetworkReachabilityGetFlags
UnsafeMutablePointer<SCNetworkReachabilityFlags>
另请注意,从Swift2开始,可以注册一个通告程序回调,将使用Swift和Swift2中的C API与Swift 2-UnsafeMutablePointer <Void>与object进行比较。
<Void>
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) }