J'essaye de convertir cet extrait de code en Swift. J'ai du mal à décoller à cause de certaines difficultés.
- (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;
}
Le premier et le principal problème que j'ai est de savoir comment définir et travailler avec des structures C. Dans la première ligne ( struct sockaddr_in zeroAddress;
) du code ci-dessus, je pense qu'ils définissent une instance appelée à zeroAddress
partir de la structure sockaddr_in (?), Je suppose. J'ai essayé de déclarer un var
comme ça.
var zeroAddress = sockaddr_in()
Mais j'obtiens l'erreur Argument manquant pour le paramètre 'sin_len' dans l'appel, ce qui est compréhensible car cette structure prend un certain nombre d'arguments. Alors j'ai réessayé.
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
Comme prévu, j'obtiens une autre variable d' erreur utilisée dans sa propre valeur initiale . Je comprends aussi la cause de cette erreur. En C, ils déclarent d'abord l'instance, puis remplissent les paramètres. Ce n'est pas possible dans Swift pour autant que je sache. Je suis donc vraiment perdu à ce stade sur ce qu'il faut faire.
J'ai lu le document officiel d'Apple sur l'interaction avec les API C dans Swift mais il n'a pas d'exemples de travail avec les structures.
Quelqu'un peut-il m'aider ici? J'apprécierais vraiment.
Je vous remercie.
MISE À JOUR: Grâce à Martin, j'ai pu surmonter le problème initial. Mais Swift ne me facilite toujours pas la tâche. Je reçois plusieurs nouvelles erreurs.
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: OK, j'ai changé cette ligne en ceci,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
La nouvelle erreur que j'obtiens à cette ligne est que «UnsafePointer» n'est pas convertible en «CFAllocator» . Comment passer NULL
à Swift?
J'ai également changé cette ligne et l'erreur a disparu maintenant.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
EDIT 2: je suis passé nil
dans cette ligne après avoir vu cette question. Mais cette réponse est en contradiction avec la réponse ici . Il dit qu'il n'y a pas d'équivalent à NULL
Swift.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
Quoi qu'il en soit, j'obtiens une nouvelle erreur disant que «sockaddr_in» n'est pas identique à «sockaddr» à la ligne ci-dessus.
Réponses:
(Cette réponse a été étendue à plusieurs reprises en raison de changements dans le langage Swift, ce qui la rendait un peu déroutante. Je l'ai maintenant réécrite et supprimé tout ce qui se réfère à Swift 1.x. L'ancien code peut être trouvé dans l'historique des modifications si quelqu'un a besoin il.)
Voici comment vous le feriez dans Swift 2.0 (Xcode 7) :
Explications:
Depuis Swift 1.2 (Xcode 6.3), les structures C importées ont un initialiseur par défaut dans Swift, qui initialise tous les champs de la structure à zéro, de sorte que la structure d'adresse de socket peut être initialisée avec
sizeofValue()
donne la taille de cette structure, il faut la convertir enUInt8
poursin_len
:AF_INET
est unInt32
, il doit être converti dans le type correct poursin_family
:withUnsafePointer(&zeroAddress) { ... }
passe l'adresse de la structure à la fermeture où elle est utilisée comme argument pourSCNetworkReachabilityCreateWithAddress()
. LaUnsafePointer($0)
conversion est nécessaire car cette fonction attend un pointeur verssockaddr
, nonsockaddr_in
.La valeur renvoyée de
withUnsafePointer()
est la valeur de retour deSCNetworkReachabilityCreateWithAddress()
et qui a le typeSCNetworkReachability?
, c'est-à-dire qu'elle est facultative. L'guard let
instruction (une nouvelle fonctionnalité de Swift 2.0) attribue la valeur déroulée à ladefaultRouteReachability
variable si ce n'est pas le casnil
. Sinon, leelse
bloc est exécuté et la fonction retourne.SCNetworkReachabilityCreateWithAddress()
renvoie un objet géré. Vous n'êtes pas obligé de le publier explicitement.À partir de Swift 2,
SCNetworkReachabilityFlags
est conforme àOptionSetType
qui a une interface de type set. Vous créez une variable d'indicateurs vide avecet vérifiez les drapeaux avec
Le deuxième paramètre de
SCNetworkReachabilityGetFlags
a le typeUnsafeMutablePointer<SCNetworkReachabilityFlags>
, ce qui signifie que vous devez passer l' adresse de la variable flags.Notez également que l'enregistrement d'un rappel de notificateur est possible à partir de Swift 2, comparez Working with C APIs from Swift and Swift 2 - UnsafeMutablePointer <Void> à object .
Mise à jour pour Swift 3/4:
Les pointeurs non sécurisés ne peuvent plus être simplement convertis en un pointeur d'un type différent (voir - SE-0107 API UnsafeRawPointer ). Voici le code mis à jour:
la source
withUnsafePointer(&zeroAddress)
appelle la fermeture suivante{ ...}
avec l'adresse dezeroAddress
comme argument. À l'intérieur de la fermeture,$0
représente cet argument. - Désolé, il est impossible d'expliquer tout cela en quelques phrases. Jetez un œil à la documentation sur les fermetures dans le livre Swift. $ 0 est un "nom d'argument abrégé".true
si le wifi n'est pas connecté et que la 4G est activée mais que l'utilisateur a spécifié que l'application ne peut pas utiliser de données cellulaires. Des solutions?let cellular = flags.contains(.IsWWAN)
Vous pouvez renvoyer un touple au lieu d'un booléen, comme:func connectedToNetwork() -> (connected: Bool, cellular: Bool)
Swift 3, IPv4, IPv6
Basé sur la réponse de Martin R:
la source
import SystemConfiguration
Cela n'a rien à voir avec Swift, mais la meilleure solution est de NE PAS utiliser l'accessibilité pour déterminer si le réseau est en ligne. Faites simplement votre connexion et gérez les erreurs en cas d'échec. L'établissement d'une connexion peut parfois déclencher les radios hors ligne dormantes.
La seule utilisation valable de l'accessibilité est de l'utiliser pour vous avertir lorsqu'un réseau passe de hors ligne à en ligne. À ce stade, vous devez réessayer les connexions ayant échoué.
la source
NSURLSession
API avecNSURLSessionConfiguration.allowsCellularAccess = false
.La meilleure solution consiste à utiliser la
ReachabilitySwift
classe , l'écritureSwift 2
et les utilisationsSCNetworkReachabilityRef
.Simple et facile:
Travailler comme un charme.
Prendre plaisir
la source
SCNetworkReachability
classe dans Swift, c'est une suggestion de dépendance à utiliser pour vérifier une connexion réseau valide.mise à jour de la réponse de juanjo pour créer une instance singleton
Usage
la source
C'est dans Swift 4.0
J'utilise ce framework https://github.com/ashleymills/Reachability.swift
et installe le pod ..
Dans AppDelegate
L'écran d'accessibilitéViewController apparaîtra si Internet n'est pas là
la source