Ich versuche, dieses Code-Snippet in Swift zu konvertieren . Ich habe aufgrund einiger Schwierigkeiten Schwierigkeiten, vom Boden abzuheben.
- (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;
}
Das erste und wichtigste Problem, das ich habe, ist das Definieren und Arbeiten mit C-Strukturen. In der ersten Zeile ( struct sockaddr_in zeroAddress;
) des obigen Codes definieren sie zeroAddress
vermutlich eine Instanz, die von der Struktur sockaddr_in (?) Aufgerufen wird. Ich habe versucht, so etwas zu erklären var
.
var zeroAddress = sockaddr_in()
Aber ich erhalte den Fehler Fehlendes Argument für den Parameter 'sin_len' im Aufruf, was verständlich ist, da diese Struktur eine Reihe von Argumenten akzeptiert . Also habe ich es erneut versucht.
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
Wie erwartet erhalte ich eine andere Fehlervariable, die innerhalb ihres eigenen Anfangswertes verwendet wird . Ich verstehe auch die Ursache dieses Fehlers. In C deklarieren sie zuerst die Instanz und füllen dann die Parameter aus. Soweit ich weiß, ist das in Swift nicht möglich. An diesem Punkt bin ich wirklich verloren, was ich tun soll.
Ich habe Apples offizielles Dokument über die Interaktion mit C-APIs in Swift gelesen, aber es gibt keine Beispiele für die Arbeit mit Strukturen.
Kann mir bitte jemand hier raushelfen? Ich würde es wirklich schätzen.
Danke dir.
UPDATE: Dank Martin konnte ich das ursprüngliche Problem überwinden. Trotzdem macht es Swift mir 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
}
EDIT 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 erhalte, ist "UnsafePointer" und kann nicht in "CFAllocator" konvertiert werden . Wie kommst du NULL
in Swift vorbei?
Auch ich habe diese Zeile geändert und der Fehler ist jetzt weg.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
EDIT 2: Ich habe nil
diese Zeile bestanden, nachdem ich diese Frage gesehen habe. Diese Antwort widerspricht jedoch der Antwort hier . Es heißt, es gibt kein Äquivalent zu NULL
Swift.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
Auf jeden Fall erhalte ich eine neue Fehlermeldung, dass 'sockaddr_in' nicht mit 'sockaddr' in der obigen Zeile identisch ist .
Antworten:
(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. Der ältere Code kann im Bearbeitungsverlauf gefunden werden, wenn jemand dies benötigt es.)
So würden Sie es in Swift 2.0 (Xcode 7) machen :
Erklärungen:
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 mit initialisiert werden kann
sizeofValue()
Gibt die Größe dieser Struktur an, muss diese konvertiert werdenUInt8
fürsin_len
:AF_INET
ist einInt32
, dies muss in den richtigen Typ konvertiert werden fürsin_family
:withUnsafePointer(&zeroAddress) { ... }
Übergibt die Adresse der Struktur an den Abschluss, für den sie als Argument verwendet wirdSCNetworkReachabilityCreateWithAddress()
. DieUnsafePointer($0)
Konvertierung ist erforderlich, da diese Funktion einen Zeiger auf erwartetsockaddr
, nichtsockaddr_in
.Der zurückgegebene Wert
withUnsafePointer()
ist der Rückgabewert vonSCNetworkReachabilityCreateWithAddress()
und hat den TypSCNetworkReachability?
, dh er ist optional. Dieguard let
Anweisung (eine neue Funktion in Swift 2.0) weist derdefaultRouteReachability
Variablen den nicht umschlossenen Wert zu , wenn dies nicht der Fall istnil
. Andernfalls wird derelse
Block ausgeführt und die Funktion kehrt zurück.SCNetworkReachabilityCreateWithAddress()
ein verwaltetes Objekt zurück. Sie müssen es nicht explizit freigeben.Ab Swift 2 hat
SCNetworkReachabilityFlags
konformOptionSetType
eine setartige Schnittstelle. Sie erstellen eine leere Flags-Variable mitund suchen Sie nach Flags mit
Der zweite Parameter von
SCNetworkReachabilityGetFlags
hat den TypUnsafeMutablePointer<SCNetworkReachabilityFlags>
, was bedeutet, dass Sie die Adresse der Flags-Variablen übergeben müssen.Beachten Sie auch, dass das Registrieren eines Notifier-Rückrufs ab Swift 2 möglich ist. Vergleichen Sie Arbeiten mit C-APIs von Swift und Swift 2 - UnsafeMutablePointer <Void> zum Objekt .
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:
quelle
withUnsafePointer(&zeroAddress)
ruft den folgenden Abschluss{ ...}
mit der AdressezeroAddress
als Argument auf. In der Schließung$0
steht für dieses Argument. - Entschuldigung, es ist unmöglich, das alles in wenigen Sätzen zu erklären. Schauen Sie sich die Dokumentation zu Schließungen im Swift-Buch an. $ 0 ist ein "Kurzargumentname".true
wenn WLAN nicht verbunden ist und 4G aktiviert ist, der Benutzer jedoch angegeben hat, dass die App möglicherweise keine Mobilfunkdaten verwendet. Gibt es Lösungen?let cellular = flags.contains(.IsWWAN)
Sie können ein Touple anstelle eines Booleschen zurückgeben, wie:func connectedToNetwork() -> (connected: Bool, cellular: Bool)
Swift 3, IPv4, IPv6
Basierend auf der Antwort von Martin R:
quelle
import SystemConfiguration
Dies hat nichts mit Swift zu tun, aber die beste Lösung besteht darin, die Erreichbarkeit NICHT zu verwenden, um festzustellen, ob das Netzwerk online ist. Stellen Sie einfach Ihre Verbindung her und behandeln Sie Fehler, wenn dies fehlschlägt. Das Herstellen einer Verbindung kann manchmal die ruhenden Offline-Funkgeräte starten.
Die einzig gültige Verwendung von Reachability besteht darin, Sie zu benachrichtigen, wenn ein Netzwerk von offline zu online wechselt. An diesem Punkt sollten Sie fehlgeschlagene Verbindungen erneut versuchen.
quelle
NSURLSession
API mit verwendenNSURLSessionConfiguration.allowsCellularAccess = false
.Die beste Lösung ist die Verwendung von
ReachabilitySwift
Klasse , geschriebenSwift 2
und verwendetSCNetworkReachabilityRef
.Simpel und einfach:
Arbeiten wie ein Zauber.
Genießen
quelle
SCNetworkReachability
Klassen in Swift verwendet werden sollen. Es handelt sich um einen Vorschlag für eine Abhängigkeit, mit der nach einer gültigen Netzwerkverbindung gesucht werden soll.Die Antwort von Juanjo wurde aktualisiert, um eine Singleton-Instanz zu erstellen
Verwendung
quelle
Dies ist in Swift 4.0
Ich verwende dieses Framework https://github.com/ashleymills/Reachability.swift
und installiere Pod ..
In AppDelegate
Der Bildschirm ReachabilityViewController wird angezeigt, wenn das Internet nicht vorhanden ist
quelle