Das erste und wichtigste Problem, das ich habe, ist die Definition und Arbeit mit C-Strukturen. In der ersten Zeile (struct sockaddr_in zeroAddress;) des obigen Codes, ich denke, sie definieren eine Instanz namens zeroAddress aus der struct sockaddr_in(?), nehme ich an. Ich habe versucht, a zu deklarieren var so was.
var zeroAddress = sockaddr_in()
Aber ich bekomme den Fehler Fehlendes Argument für Parameter ‘sin_len’ im Aufruf was verständlich ist, weil diese Struktur eine Reihe von Argumenten benötigt. Also versuchte ich es erneut.
Wie erwartet bekomme ich einen anderen Fehler Variable, die innerhalb ihres eigenen Anfangswerts verwendet wird. Ich verstehe die Ursache dieses Fehlers auch. In C deklarieren sie zuerst die Instanz und füllen dann die Parameter auf. In Swift ist das meines Wissens nach nicht möglich. Also bin ich an diesem Punkt wirklich verloren, was ich tun soll.
Ich las Apples offizielle dokumentieren zur Interaktion mit C-APIs in Swift, aber es gibt keine Beispiele für die Arbeit mit Strukturen.
Kann mir hier bitte jemand weiterhelfen? Ich würde es wirklich zu schätzen wissen.
Vielen Dank.
AKTUALISIEREN: Dank Martin konnte ich das anfängliche Problem überwinden. Aber Swift macht es mir trotzdem nicht leichter. Ich erhalte mehrere neue Fehler.
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
}
BEARBEITEN 1: Okay, ich habe diese Zeile in diese geändert,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
Der neue Fehler, den ich in dieser Zeile bekomme, ist „UnsafePointer“ ist nicht in „CFAllocator“ konvertierbar. Wie Sie bestehen NULL auf Swift?
Auch diese Zeile habe ich geändert und der Fehler ist jetzt weg.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
BEARBEITEN 2: Ich bestand nil in dieser Zeile, nachdem Sie diese Frage gesehen haben. Aber diese Antwort widerspricht der Antwort hier. Es heißt, es gibt kein Äquivalent zu NULL in Swift.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
Jedenfalls bekomme ich eine neue Fehlermeldung ‘sockaddr_in’ ist nicht identisch mit ‘sockaddr’ in der oberen Zeile.
Ich habe einen Fehler in Zeile if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) dh unärer Operator! kann nicht auf einen Operanden vom Typ Boolean angewendet werden. . . . bitte helfen.
– Seebok
18. April 2016 um 9:16 Uhr
Martin R
(Diese Antwort wurde aufgrund von Änderungen in der Swift-Sprache wiederholt erweitert, was sie etwas verwirrend machte. Ich habe sie jetzt umgeschrieben und alles entfernt, was sich auf Swift 1.x bezieht. Den älteren Code finden Sie im Bearbeitungsverlauf, falls jemand ihn braucht es.)
So würdest du es machen 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)
}
Erläuterungen:
Ab Swift 1.2 (Xcode 6.3) haben importierte C-Strukturen einen Standardinitialisierer in Swift, der alle Felder der Struktur auf Null initialisiert, sodass die Socket-Adressstruktur damit initialisiert werden kann
var zeroAddress = sockaddr_in()
sizeofValue() gibt die Größe dieser Struktur an, in die umgerechnet werden muss UInt8 zum sin_len:
AF_INET ist ein Int32muss dies in den richtigen Typ für konvertiert werden sin_family:
zeroAddress.sin_family = sa_family_t(AF_INET)
withUnsafePointer(&zeroAddress) { ... } übergibt die Adresse der Struktur an die Closure, wo sie als Argument für verwendet wird SCNetworkReachabilityCreateWithAddress(). Das UnsafePointer($0)
Konvertierung ist erforderlich, da diese Funktion einen Zeiger auf erwartet sockaddrnicht sockaddr_in.
Der Wert, der von zurückgegeben wird withUnsafePointer() ist der Rückgabewert von SCNetworkReachabilityCreateWithAddress() und das hat den typ SCNetworkReachability?, dh es ist optional. Das guard let -Anweisung (eine neue Funktion in Swift 2.0) weist den ausgepackten Wert der zu defaultRouteReachability variabel, wenn nicht nil. Ansonsten der else Block wird ausgeführt und die Funktion kehrt zurück.
Ab Swift 2, SCNetworkReachabilityCreateWithAddress() gibt ein verwaltetes Objekt zurück. Sie müssen es nicht explizit freigeben.
Ab Swift 2, SCNetworkReachabilityFlags entspricht OptionSetType die eine mengenähnliche Schnittstelle hat. Sie erstellen eine leere flags-Variable mit
var flags : SCNetworkReachabilityFlags = []
und nach Flags suchen mit
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
Der zweite Parameter von SCNetworkReachabilityGetFlags hat den Typ UnsafeMutablePointer<SCNetworkReachabilityFlags>was bedeutet, dass Sie die passieren müssen die Anschrift der flags-Variablen.
Beachten Sie auch, dass das Registrieren eines Notifier-Callbacks ab Swift 2 möglich ist, vergleiche Arbeiten mit C-APIs von Swift und Swift 2 – UnsafeMutablePointer to object.
Update für Swift 3/4:
Unsichere Zeiger können nicht mehr einfach in einen Zeiger eines anderen Typs konvertiert werden (siehe – SE-0107 UnsafeRawPointer-API). Hier der aktualisierte Code:
@Isuru: UnsafePointer ist das Swift-Äquivalent eines C-Zeigers. withUnsafePointer(&zeroAddress) ruft die folgende Schließung auf { ...} mit der Adresse von zeroAddress als argument. Innerhalb des Verschlusses, $0 steht für dieses Argument. – Entschuldigung, es ist unmöglich, das alles in ein paar Sätzen zu erklären. Sehen Sie sich die Dokumentation über Closures im Swift-Buch an. $0 ist ein “Kurzform-Argumentname”.
–Martin R
2. September 2014 um 19:14 Uhr
@JAL: Sie haben Recht, Apple hat geändert, wie ein “Boolean” Swift zugeordnet wird. Vielen Dank für Ihr Feedback, ich werde die Antwort entsprechend aktualisieren.
–Martin R
7. August 2015 um 19:21 Uhr
Dies kehrt zurück true wenn WLAN nicht verbunden und 4G eingeschaltet ist, aber der Benutzer angegeben hat, dass die App keine Mobilfunkdaten verwenden darf. Irgendwelche Lösungen?
– Max Chuquimia
13. August 2015 um 6:36 Uhr
@Jugale: Sie könnten so etwas tun: let cellular = flags.contains(.IsWWAN) Sie können anstelle eines booleschen Werts auch ein Touple zurückgeben, wie zum Beispiel: func connectedToNetwork() -> (connected: Bool, cellular: Bool)
– EdFunke
25. November 2015 um 9:17 Uhr
@Tejas: Sie können anstelle der “Nulladresse” eine beliebige IP-Adresse verwenden oder SCNetworkReachabilityCreateWithName() mit einem Hostnamen als Zeichenfolge verwenden. Beachten Sie jedoch, dass SCNetworkReachability nur prüft, ob ein an diese Adresse gesendetes Paket das lokale Gerät verlassen kann. Es garantiert nicht, dass das Datenpaket tatsächlich vom Host empfangen wird.
Funktioniert für mich auch am besten für NET64/IPV6, nicht vergessen import SystemConfiguration
– Bhavin_m
16. Dezember 2016 um 11:34 Uhr
@juanjo, wie legst du einen Host fest, den du mit deinem Code erreichen möchtest
– Benutzer2924482
23. Dezember 2019 um 19:36 Uhr
Mithra Singam
Swift 5, mit 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))
}
Dafür braucht es mehr Upvotes. Dies ist viel sauberer und benutzerfreundlicher als das SystemConfiguration-Framework.
– Xaxxus
28. Januar 2021 um 14:24 Uhr
Einverstanden. Funktioniert in xCode 13.3 und Swift 5
– Jason
22. Mai um 18:32 Uhr
Dies hat nichts mit Swift zu tun, aber die beste Lösung besteht darin, Reachability NICHT zu verwenden, um festzustellen, ob das Netzwerk online ist. Stellen Sie einfach Ihre Verbindung her und behandeln Sie Fehler, wenn sie fehlschlägt. Das Herstellen einer Verbindung kann manchmal die inaktiven Offline-Funkgeräte starten.
Die einzig gültige Verwendung von Erreichbarkeit besteht darin, Sie zu benachrichtigen, wenn ein Netzwerk von offline zu online wechselt. An diesem Punkt sollten Sie fehlgeschlagene Verbindungen erneut versuchen.
Bonke
Die beste Lösung ist die Verwendung ReachabilitySwiftKlassegeschrieben in Swift 2und verwendet SCNetworkReachabilityRef.
Simpel und einfach:
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()
Arbeiten wie ein Zauber.
Genießen
Ich bevorzuge die akzeptierte Antwort, da keine Abhängigkeiten von Drittanbietern integriert werden müssen. Außerdem beantwortet dies nicht die Frage nach der Verwendung SCNetworkReachability Klasse in Swift ist es ein Vorschlag für eine Abhängigkeit, die verwendet werden kann, um nach einer gültigen Netzwerkverbindung zu suchen.
– JAL
15. Oktober 2015 um 15:34 Uhr
anoop4real
die Antwort von Juanjo aktualisiert, um eine Singleton-Instanz zu erstellen
Ich bevorzuge die akzeptierte Antwort, da keine Abhängigkeiten von Drittanbietern integriert werden müssen. Außerdem beantwortet dies nicht die Frage nach der Verwendung SCNetworkReachability Klasse in Swift ist es ein Vorschlag für eine Abhängigkeit, die verwendet werden kann, um nach einer gültigen Netzwerkverbindung zu suchen.
Ich habe einen Fehler in Zeile if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) dh unärer Operator! kann nicht auf einen Operanden vom Typ Boolean angewendet werden. . . . bitte helfen.
– Seebok
18. April 2016 um 9:16 Uhr