Isu*_*uru 97 c struct reachability ios swift
我正在尝试将此代码段转换为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;
}
Run Code Online (Sandbox Code Playgroud)
我遇到的第一个和主要问题是如何定义和使用C结构.在struct sockaddr_in zeroAddress;
上面代码的第一行()中,我认为他们正在定义一个zeroAddress
从struct sockaddr_in(?)调用的实例,我假设.我试着宣布var
这样的话.
var zeroAddress = sockaddr_in()
Run Code Online (Sandbox Code Playgroud)
但是我在调用中得到参数'sin_len'的错误缺失参数,这是可以理解的,因为该结构需要许多参数.所以我又试了一次.
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,我在其自己的初始值中使用了一些其他错误变量.我也理解这个错误的原因.在C中,它们首先声明实例,然后填充参数.据我所知,它在Swift中是不可能的.所以我真的迷失了这一点.
我阅读了Apple 关于在Swift中与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
}
Run Code Online (Sandbox Code Playgroud)
编辑1: 好的,我改变了这一行,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
Run Code Online (Sandbox Code Playgroud)
我在这一行得到的新错误是'UnsafePointer'无法转换为'CFAllocator'.你如何通过NULL
Swift?
我也改变了这一行,错误现在消失了.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
Run Code Online (Sandbox Code Playgroud)
编辑2:nil
看到这个问题后我通过了这一行.但是这个答案的答案矛盾在这里.它说NULL
在Swift中没有相同的东西.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
Run Code Online (Sandbox Code Playgroud)
无论如何,我得到一个新的错误,说'sockaddr_in'与上面一行的'sockaddr'不同.
Mar*_*n R 232
(由于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)
}
Run Code Online (Sandbox Code Playgroud)
说明:
从Swift 1.2(Xcode 6.3)开始,导入的C结构在Swift中有一个默认的初始化器,它将所有struct的字段初始化为零,因此套接字地址结构可以初始化为
var zeroAddress = sockaddr_in()
Run Code Online (Sandbox Code Playgroud)sizeofValue()
给出了这个结构的大小,这必须转换UInt8
为sin_len
:
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
Run Code Online (Sandbox Code Playgroud)AF_INET
是Int32
,这必须转换为正确的类型sin_family
:
zeroAddress.sin_family = sa_family_t(AF_INET)
Run Code Online (Sandbox Code Playgroud)withUnsafePointer(&zeroAddress) { ... }
将结构的地址传递给闭包,在闭包中将其用作参数
SCNetworkReachabilityCreateWithAddress()
.该UnsafePointer($0)
转换是必要的,因为该功能需要一个指针
sockaddr
,而不是sockaddr_in
.
从返回的值withUnsafePointer()
是从返回值SCNetworkReachabilityCreateWithAddress()
和具有类型SCNetworkReachability?
,即它是一个可选的.该guard let
语句(Swift 2.0中的一个新功能)将未包装的值分配给defaultRouteReachability
变量(如果不是)nil
.否则else
执行该块并返回该函数.
SCNetworkReachabilityCreateWithAddress()
返回一个托管对象.您不必明确释放它.从Swift 2开始,SCNetworkReachabilityFlags
符合
OptionSetType
具有类似集合的界面.您使用创建一个空标志变量
var flags : SCNetworkReachabilityFlags = []
Run Code Online (Sandbox Code Playgroud)
并检查标志
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
Run Code Online (Sandbox Code Playgroud)第二个参数SCNetworkReachabilityGetFlags
有类型
UnsafeMutablePointer<SCNetworkReachabilityFlags>
,这意味着你必须传递flags变量的地址.
另请注意,从Swift 2开始,可以注册通知程序回调,比较使用Swift和Swift 2中的C API - 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)
}
Run Code Online (Sandbox Code Playgroud)
Mit*_*gam 15
斯威夫特 5,使用NWPathMonitor
import Network
func configureNetworkMonitor(){
let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in
if path.status != .satisfied {
print("not connected")
}
else if path.usesInterfaceType(.cellular) {
print("Cellular")
}
else if path.usesInterfaceType(.wifi) {
print("WIFI")
}
else if path.usesInterfaceType(.wiredEthernet) {
print("Ethernet")
}
else if path.usesInterfaceType(.other){
print("Other")
}else if path.usesInterfaceType(.loopback){
print("Loop Back")
}
}
monitor.start(queue: DispatchQueue.global(qos: .background))
}
Run Code Online (Sandbox Code Playgroud)
jua*_*njo 12
Swift 3,IPv4,IPv6
根据Martin 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)
}
})
}
Run Code Online (Sandbox Code Playgroud)
这与Swift无关,但最好的解决方案是不使用Reachability来确定网络是否在线.如果失败,只需建立连接并处理错误.建立连接有时可以启动休眠的离线无线电.
可达性的一个有效用途是使用它来在网络从离线转换到在线时通知您.此时,您应该重试失败的连接.
归档时间: |
|
查看次数: |
38304 次 |
最近记录: |