ios स्विफ्ट में SCNetworkReachability का उपयोग कैसे करें




struct swift (4)

स्विफ्ट 3, आईपीवी 4, आईपीवी 6

मार्टिन आर के उत्तर के आधार पर:

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 कोड स्निपेट को स्विफ्ट में बदलने की कोशिश कर रहा हूं। मैं कुछ कठिनाइयों के कारण जमीन से उतरने पर संघर्ष कर रहा हूं।

- (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;
}

मेरे पास पहला और मुख्य मुद्दा है जो सी structs के साथ परिभाषित और काम करने के तरीके पर है। उपरोक्त कोड की पहली पंक्ति ( struct sockaddr_in zeroAddress; ) में, मुझे लगता है कि वे संरचना sockaddr_in (?) से zeroAddress नामक एक उदाहरण को परिभाषित कर रहे हैं, मुझे लगता है। मैंने इस तरह एक 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)

जैसा कि अपेक्षित है मुझे कुछ अन्य त्रुटि मिलती है वैरिएबल अपने प्रारंभिक मूल्य के भीतर उपयोग किया जाता है । मैं भी उस त्रुटि का कारण समझता हूं। सी में, वे पहले उदाहरण घोषित करते हैं और फिर पैरामीटर भरते हैं। जहां तक ​​मुझे पता है स्विफ्ट में यह संभव नहीं है। तो मैं इस बिंदु पर वास्तव में खो गया हूं कि क्या करना है।

मैंने स्विफ्ट में सी एपीआई के साथ बातचीत document पर ऐप्पल के आधिकारिक document को पढ़ा लेकिन इसमें structs के साथ काम करने में कोई उदाहरण नहीं है।

क्या कोई मेरी मदद कर सकता है? मैं वास्तव में इसकी सराहना करता हूं।

धन्यवाद।

अद्यतन: मार्टिन के लिए धन्यवाद मैं प्रारंभिक समस्या से पहले प्राप्त करने में सक्षम था। लेकिन अभी भी स्विफ्ट मेरे लिए यह आसान नहीं बना रहा है। मुझे कई नई त्रुटियां मिल रही हैं।

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' में परिवर्तनीय नहीं है । स्विफ्ट में आप कैसे पास करते हैं?

इसके अलावा मैंने इस लाइन को बदल दिया और त्रुटि अब चली गई है।

let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)

संपादित करें 2: this प्रश्न को देखने के बाद मैंने इस पंक्ति में nil पारित किया। लेकिन वह जवाब here जवाब के साथ विरोधाभास करता here । यह कहते हैं कि स्विफ्ट में NULL बराबर नहीं है।

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

वैसे भी मुझे एक नई त्रुटि मिल रही है कि 'sockaddr_in' उपर्युक्त रेखा पर 'सॉकड्रर' के समान नहीं है


सिंगलटन उदाहरण बनाने के लिए जुआनजो का जवाब अपडेट किया गया

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(){

}

(स्विफ्ट भाषा में बदलावों के कारण यह उत्तर बार-बार बढ़ाया गया था, जिसने इसे थोड़ा उलझन में डाल दिया। मैंने अब इसे फिर से लिखा है और स्विफ्ट 1.x को संदर्भित करने वाली सभी चीज़ों को हटा दिया है। पुराने कोड को संपादन इतिहास में पाया जा सकता है अगर किसी को चाहिए यह।)

स्विफ्ट 2.0 (एक्सकोड 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) के रूप में, आयातित सी structs में स्विफ्ट में एक डिफ़ॉल्ट प्रारंभकर्ता है, जो सभी संरचनाओं के फ़ील्ड को शून्य में प्रारंभ करता है, इसलिए सॉकेट पता संरचना को प्रारंभ किया जा सकता है

    var zeroAddress = sockaddr_in()
    
  • sizeofValue() इस संरचना का आकार देता है, इसे UInt8 लिए sin_len परिवर्तित करना sin_len :

    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    
  • AF_INET एक Int32 , इसे sin_family लिए सही प्रकार में परिवर्तित किया sin_family :

    zeroAddress.sin_family = sa_family_t(AF_INET)
    
  • withUnsafePointer(&zeroAddress) { ... } संरचना के पते को बंद करने के लिए पास करता है जहां इसे SCNetworkReachabilityCreateWithAddress() लिए तर्क के रूप में उपयोग किया जाता है। UnsafePointer($0) रूपांतरण की आवश्यकता है क्योंकि वह फ़ंक्शन किसी पॉइंटर को sockaddr अपेक्षा करता है, न कि sockaddr_in

  • withUnsafePointer() से लौटाया गया मूल्य withUnsafePointer() से वापसी मूल्य है और इसमें टाइप SCNetworkReachability? , यानी यह एक वैकल्पिक है। guard let स्टेटमेंट (स्विफ्ट 2.0 में एक नई सुविधा) defaultRouteReachability वैरिएबल को अनचाहे मान निर्दिष्ट करती है यदि यह nil नहीं है। अन्यथा else ब्लॉक निष्पादित किया गया है और समारोह वापस आता है।

  • स्विफ्ट 2 के रूप में, SCNetworkReachabilityCreateWithAddress() एक प्रबंधित ऑब्जेक्ट देता है। आपको इसे स्पष्ट रूप से जारी नहीं करना है।
  • स्विफ्ट 2 के रूप में, SCNetworkReachabilityFlags अनुरूप है जिसमें एक सेट-जैसे इंटरफ़ेस है। आप के साथ एक खाली झंडे चर बनाते हैं

    var flags : SCNetworkReachabilityFlags = []
    

    और झंडे के साथ जांचें

    let isReachable = flags.contains(.Reachable)
    let needsConnection = flags.contains(.ConnectionRequired)
    
  • SCNetworkReachabilityGetFlags दूसरे पैरामीटर में SCNetworkReachabilityGetFlags UnsafeMutablePointer<SCNetworkReachabilityFlags> प्रकार है, जिसका अर्थ है कि आपको फ़्लैग चर के पते को पास करना होगा।

ध्यान दें कि एक नोटिफ़ायर कॉलबैक पंजीकृत करना स्विफ्ट 2 के रूप में संभव है, स्विफ्ट और स्विफ्ट 2 से सी एपीआई के साथ काम करने की तुलना करें - UnsafeMutablePointer <Void> ऑब्जेक्ट पर

स्विफ्ट 3/4 के लिए अद्यतन करें:

असुरक्षित पॉइंटर्स को अब किसी भिन्न प्रकार के पॉइंटर में परिवर्तित नहीं किया जा सकता है (देखें - एसई -0107 असुरक्षित पॉइंट एपीआई )। यहां अद्यतन कोड:

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

स्विफ्ट के साथ इसका कोई लेना-देना नहीं है, लेकिन सबसे अच्छा समाधान यह निर्धारित करने के लिए पहुंचने का उपयोग नहीं करना है कि नेटवर्क ऑनलाइन है या नहीं। बस अपना कनेक्शन बनाएं और त्रुटियों को संभाल लें यदि यह विफल हो जाता है। एक कनेक्शन बनाना कभी-कभी निष्क्रिय ऑफलाइन रेडियो को आग लग सकता है।

रीचैबिलिटी का एक वैध उपयोग यह है कि जब नेटवर्क ऑफ़लाइन से ऑनलाइन संक्रमण होता है तो आपको सूचित करने के लिए इसका उपयोग करना है। उस बिंदु पर आपको असफल कनेक्शन पुनः प्रयास करना चाहिए।





reachability