Estoy intentando convertir este fragmento de código a Swift. Estoy luchando para despegar debido a algunas dificultades.
- (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;
}
El primer y principal problema que tengo es cómo definir y trabajar con estructuras C. En la primera línea ( struct sockaddr_in zeroAddress;
) del código anterior, creo que están definiendo una instancia llamada zeroAddress
desde la estructura sockaddr_in (?), Supongo. Intenté declarar algo var
así.
var zeroAddress = sockaddr_in()
Pero obtengo el error Faltante argumento para el parámetro 'sin_len' en la llamada, lo cual es comprensible porque esa estructura toma varios argumentos. Así que lo intenté de nuevo.
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
Como esperaba, obtengo otra Variable de error utilizada dentro de su propio valor inicial . También entiendo la causa de ese error. En C, primero declaran la instancia y luego completan los parámetros. No es posible en Swift que yo sepa. Así que estoy realmente perdido en este punto sobre qué hacer.
Leí el documento oficial de Apple sobre la interacción con las API de C en Swift, pero no tiene ejemplos sobre cómo trabajar con estructuras.
¿Alguien puede ayudarme aquí? Realmente lo agradecería.
Gracias.
ACTUALIZACIÓN: Gracias a Martin pude superar el problema inicial. Pero aún así Swift no me lo pone más fácil. Recibo varios errores nuevos.
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
}
EDITAR 1: Bien, cambié esta línea a esto,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
El nuevo error que recibo en esta línea es 'UnsafePointer' no se puede convertir a 'CFAllocator' . ¿Cómo pasar NULL
en Swift?
También cambié esta línea y el error desapareció ahora.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
EDICIÓN 2: Pasé nil
en esta línea después de ver esta pregunta. Pero esa respuesta contradice la respuesta aquí . Dice que no hay equivalente NULL
en Swift.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
De todos modos , aparece un nuevo error que dice que 'sockaddr_in' no es idéntico a 'sockaddr' en la línea anterior.
Respuestas:
(Esta respuesta se extendió repetidamente debido a cambios en el lenguaje Swift, lo que lo hizo un poco confuso. Ahora lo reescribí y eliminé todo lo que se refiere a Swift 1.x. El código anterior se puede encontrar en el historial de edición si alguien necesita eso.)
Así es como lo haría en Swift 2.0 (Xcode 7) :
Explicaciones:
A partir de Swift 1.2 (Xcode 6.3), las estructuras C importadas tienen un inicializador predeterminado en Swift, que inicializa todos los campos de la estructura a cero, por lo que la estructura de la dirección del socket se puede inicializar con
sizeofValue()
da el tamaño de esta estructura, esto debe convertirse aUInt8
parasin_len
:AF_INET
es unInt32
, debe convertirse al tipo correcto parasin_family
:withUnsafePointer(&zeroAddress) { ... }
pasa la dirección de la estructura al cierre donde se usa como argumento paraSCNetworkReachabilityCreateWithAddress()
. LaUnsafePointer($0)
conversión es necesaria porque esa función espera un punterosockaddr
, nosockaddr_in
.El valor devuelto de
withUnsafePointer()
es el valor de retorno deSCNetworkReachabilityCreateWithAddress()
y que tiene el tipoSCNetworkReachability?
, es decir, es opcional. Laguard let
declaración (una nueva característica en Swift 2.0) asigna el valor sin envolver a ladefaultRouteReachability
variable si no es asínil
. De lo contrario, elelse
bloque se ejecuta y la función vuelve.SCNetworkReachabilityCreateWithAddress()
devuelve un objeto administrado. No tiene que publicarlo explícitamente.A partir de Swift 2, se
SCNetworkReachabilityFlags
ajusta a loOptionSetType
que tiene una interfaz tipo set. Creas una variable de banderas vacía cony busque banderas con
El segundo parámetro de
SCNetworkReachabilityGetFlags
tiene el tipoUnsafeMutablePointer<SCNetworkReachabilityFlags>
, lo que significa que debe pasar la dirección de la variable banderas.Tenga en cuenta también que es posible registrar una devolución de llamada de notificador a partir de Swift 2, compare Trabajar con las API de C de Swift y Swift 2 - UnsafeMutablePointer <Void> al objeto .
Actualización para Swift 3/4:
Los punteros inseguros ya no se pueden convertir simplemente en un puntero de un tipo diferente (consulte - SE-0107 API UnsafeRawPointer ). Aquí el código actualizado:
fuente
withUnsafePointer(&zeroAddress)
llama al siguiente cierre{ ...}
con la dirección dezeroAddress
como argumento. Dentro del cierre,$0
defiende ese argumento. - Lo siento, es imposible explicar todo eso en unas pocas frases. Eche un vistazo a la documentación sobre cierres en el libro Swift. $ 0 es un "nombre de argumento abreviado".true
si el wifi no está conectado y 4G está encendido pero el usuario ha especificado que la aplicación no puede usar datos móviles. ¿Alguna solución?let cellular = flags.contains(.IsWWAN)
Puedes devolver un touple en lugar de un booleano, como:func connectedToNetwork() -> (connected: Bool, cellular: Bool)
Swift 3, IPv4, IPv6
Basado en la respuesta de Martin R:
fuente
import SystemConfiguration
Esto no tiene nada que ver con Swift, pero la mejor solución es NO usar Accesibilidad para determinar si la red está en línea. Simplemente haga su conexión y maneje los errores si falla. Hacer una conexión a veces puede encender las radios fuera de línea inactivas.
El único uso válido de Accesibilidad es usarlo para notificarle cuando una red cambia de fuera de línea a en línea. En ese momento, debe volver a intentar las conexiones fallidas.
fuente
NSURLSession
API conNSURLSessionConfiguration.allowsCellularAccess = false
.La mejor solución es usar
ReachabilitySwift
class , escritoSwift 2
y usesSCNetworkReachabilityRef
.Simple y fácil:
Trabajando como un encanto.
Disfrutar
fuente
SCNetworkReachability
clase en Swift, es una sugerencia de una dependencia para usar para verificar una conexión de red válida.actualizó la respuesta de juanjo para crear una instancia de singleton
Uso
fuente
Esto es en Swift 4.0
Estoy usando este marco https://github.com/ashleymills/Reachability.swift
e instalo Pod ..
En AppDelegate
La pantalla reachabilityViewController aparecerá si no hay Internet
fuente