Swift에서 SCNetworkReachability를 사용하는 방법
이 코드 스 니펫을 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
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에서는 불가능합니다. 그래서 저는이 시점에서 무엇을해야할지 정말로 길을 잃었습니다.
Swift에서 C API와의 상호 작용에 대한 Apple의 공식 문서 를 읽었 지만 구조체 작업에 대한 예제가 없습니다.
누구든지 여기서 나를 도울 수 있습니까? 정말 감사하겠습니다.
감사합니다.
업데이트 : Martin 덕분에 초기 문제를 극복 할 수있었습니다. 그러나 여전히 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'로 변환되지 않습니다 . NULL
Swift를 어떻게 전달 합니까?
또한이 줄을 변경하고 오류가 사라졌습니다.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
편집 2 : 이 질문 nil
을 본 후이 줄을 통과 했습니다 . 그러나 그 대답은 여기 의 대답과 모순 됩니다 . 그것은 Swift에 상응하는 것이 없다고 말합니다 .NULL
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의 기본 이니셜 라이저가 있으며, 이는 구조체의 모든 필드를 0으로 초기화하므로 소켓 주소 구조를 다음으로 초기화 할 수 있습니다.
var zeroAddress = sockaddr_in()
sizeofValue()
이러한 구조의 크기는,이 변환되어야 제공UInt8
용sin_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
블록이 실행되고 함수가 반환됩니다.- Swift 2부터는
SCNetworkReachabilityCreateWithAddress()
관리되는 객체를 반환합니다. 명시 적으로 해제 할 필요는 없습니다. Swift 2
SCNetworkReachabilityFlags
부터는OptionSetType
set-like 인터페이스를 가지고 있습니다. 다음을 사용하여 빈 플래그 변수를 만듭니다.var flags : SCNetworkReachabilityFlags = []
플래그를 확인하십시오.
let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired)
의 두 번째 매개 변수
SCNetworkReachabilityGetFlags
에는 유형이 있습니다UnsafeMutablePointer<SCNetworkReachabilityFlags>
. 이는 flags 변수 의 주소 를 전달해야 함을 의미 합니다.
참고도 통보 콜백을 등록하는 것이 가능하다 (2)의 신속한 같이 비교 스위프트에서 C API를 사용한 작업을 하고 신속한 2 - <보이드> UnsafeMutablePointer을 개체 .
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)
}
스위프트 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)
}
})
}
This has nothing to do with Swift, but the best solution is to NOT use Reachability to determine whether the network is online. Just make your connection and handle errors if it fails. Making a connection can at times fire up the dormant offline radios.
The one valid use of Reachability is to use it to notify you when a network transitions from offline to online. At that point you should retry failed connections.
The best solution is to use ReachabilitySwift
class, written in Swift 2
, and uses SCNetworkReachabilityRef
.
Simple and easy:
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()
Working like a charm.
Enjoy
updated juanjo's answer to create singleton instance
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)
}
})
}
}
Usage
if Reachability.shared.isConnectedToNetwork(){
}
This is in Swift 4.0
I am using this framework https://github.com/ashleymills/Reachability.swift
And Install Pod ..
In 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")
}
}
}
The reachabilityViewController screen will appear if internet is not there
참고URL : https://stackoverflow.com/questions/25623272/how-to-use-scnetworkreachability-in-swift
'Programming' 카테고리의 다른 글
다른 페이지에서 로그인이 필요한 페이지에 액세스하기위한 CURL (0) | 2020.08.22 |
---|---|
Android Studio에서 Gradle 작업 실행을 중지하는 방법은 무엇입니까? (0) | 2020.08.22 |
Xcode 6 스토리 보드 확대 / 축소를 활성화하는 방법은 무엇입니까? (0) | 2020.08.22 |
JQuery를 사용한 노란색 페이드 효과 (0) | 2020.08.22 |
C #에서 문자열의 ASCII 값을 얻는 방법 (0) | 2020.08.22 |