Próbuję przekonwertować ten fragment kodu na Swift. Z powodu pewnych trudności walczę z oderwaniem się od ziemi.
- (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;
}
Pierwsza i główna kwestia dotyczy tego, jak definiować i pracować ze strukturami C. Zakładam, że w pierwszym wierszu ( struct sockaddr_in zeroAddress;
) powyższego kodu definiują instancję zeroAddress
wywołaną ze struktury struct sockaddr_in (?). Próbowałem zadeklarować coś var
takiego.
var zeroAddress = sockaddr_in()
Ale pojawia się błąd Brakujący argument dla parametru „sin_len” w wywołaniu, co jest zrozumiałe, ponieważ ta struktura przyjmuje wiele argumentów. Więc spróbowałem ponownie.
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
Zgodnie z oczekiwaniami pojawia się inna zmienna błędu używana w jej własnej wartości początkowej . Rozumiem też przyczynę tego błędu. W C najpierw deklarują instancję, a następnie wypełniają parametry. O ile wiem, nie jest to możliwe w Swift. W tej chwili naprawdę nie wiem, co robić.
Czytałem oficjalny dokument firmy Apple dotyczący interakcji z interfejsami API języka C w języku Swift, ale nie ma on przykładów pracy ze strukturami.
Czy ktoś może mi tutaj pomóc? Naprawdę to docenię.
Dziękuję Ci.
AKTUALIZACJA: Dzięki Martinowi udało mi się pokonać początkowy problem. Ale Swift nadal mi nie ułatwia. Otrzymuję wiele nowych błędów.
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
}
EDYCJA 1: OK, zmieniłem ten wiersz na ten,
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
Nowy błąd, który otrzymuję w tym wierszu, to „UnsafePointer”, którego nie można zamienić na „CFAllocator” . Jak przejść NULL
w Swift?
Zmieniłem też tę linię i błąd zniknął.
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
EDYCJA 2: Przeszedłem nil
w tej linii po zobaczeniu tego pytania. Ale ta odpowiedź jest sprzeczna z odpowiedzią tutaj . Mówi, że nie ma odpowiednika NULL
w Swift.
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
W każdym razie pojawia się nowy błąd mówiący , że „sockaddr_in” nie jest identyczny z „sockaddr” w powyższym wierszu.
Odpowiedzi:
(Ta odpowiedź była wielokrotnie przedłużana z powodu zmian w języku Swift, co spowodowało, że była nieco zagmatwana. Teraz przepisałem ją i usunąłem wszystko, co odnosi się do Swift 1.x. Starszy kod można znaleźć w historii edycji, jeśli ktoś potrzebuje to.)
Oto jak można to zrobić w Swift 2.0 (Xcode 7) :
Objaśnienia:
Począwszy od Swift 1.2 (Xcode 6.3), zaimportowane struktury C mają domyślny inicjator w Swift, który inicjalizuje wszystkie pola struktury na zero, więc strukturę adresu gniazda można zainicjować za pomocą
sizeofValue()
podaje rozmiar tej struktury, którą należy przekonwertowaćUInt8
nasin_len
:AF_INET
jest anInt32
, to należy przekonwertować na właściwy typ dlasin_family
:withUnsafePointer(&zeroAddress) { ... }
przekazuje adres struktury do zamknięcia, gdzie jest używany jako argument forSCNetworkReachabilityCreateWithAddress()
.UnsafePointer($0)
Konieczna jest konwersja, ponieważ ta funkcja oczekuje, że wskaźnik nasockaddr
niesockaddr_in
.Wartość zwracana z
withUnsafePointer()
jest wartością zwracaną przezSCNetworkReachabilityCreateWithAddress()
i ma typSCNetworkReachability?
, tj. Jest opcjonalna.guard let
Oświadczenie (nowa funkcja Swift 2.0) przypisuje wartość nieopakowanych dodefaultRouteReachability
zmiennej, jeśli nie jestnil
. W przeciwnym razieelse
blok jest wykonywany i funkcja zwraca.SCNetworkReachabilityCreateWithAddress()
zwraca zarządzany obiekt. Nie musisz go jawnie publikować.Od wersji Swift 2
SCNetworkReachabilityFlags
jest zgodny zOptionSetType
interfejsem podobnym do zestawu. Tworzysz pustą zmienną flag za pomocąi sprawdź flagi z
Drugi parametr
SCNetworkReachabilityGetFlags
ma typUnsafeMutablePointer<SCNetworkReachabilityFlags>
, co oznacza, że musisz przekazać adres zmiennej flag.Należy również zauważyć, że rejestracja wywołania zwrotnego powiadamiającego jest możliwa od wersji Swift 2, porównaj pracę z interfejsami API języka C z języków Swift i Swift 2 - UnsafeMutablePointer <Void> z obiektem .
Aktualizacja dla Swift 3/4:
Niebezpiecznych wskaźników nie można już po prostu przekonwertować na wskaźnik innego typu (patrz - SE-0107 UnsafeRawPointer API ). Tutaj zaktualizowany kod:
źródło
withUnsafePointer(&zeroAddress)
wywołuje następujące zamknięcie{ ...}
z adresemzeroAddress
as argument. Wewnątrz zamknięcia$0
oznacza ten argument. - Przepraszam, nie da się tego wszystkiego wyjaśnić w kilku zdaniach. Zapoznaj się z dokumentacją dotyczącą zamknięć w książce Swift. $ 0 to „skrócona nazwa argumentu”.true
jeśli Wi-Fi nie jest podłączone i 4G jest włączone, ale użytkownik określił, że aplikacja może nie korzystać z danych komórkowych. Jakieś rozwiązania?let cellular = flags.contains(.IsWWAN)
Możesz zwrócić tarę zamiast wartości logicznej, na przykład:func connectedToNetwork() -> (connected: Bool, cellular: Bool)
Swift 3, IPv4, IPv6
Na podstawie odpowiedzi Martina R:
źródło
import SystemConfiguration
Nie ma to nic wspólnego z Swift, ale najlepszym rozwiązaniem jest NIEUŻYWANIE Zasięg do określenia, czy sieć jest online. Po prostu nawiąż połączenie i napraw błędy, jeśli się nie powiedzie. Nawiązanie połączenia może czasami spowodować odpalenie nieaktywnych radiotelefonów.
Jedynym ważnym zastosowaniem Reachability jest używanie go do powiadamiania Cię o przejściu sieci z trybu offline do online. W tym momencie należy ponowić nieudane połączenia.
źródło
NSURLSession
interfejsu API zNSURLSessionConfiguration.allowsCellularAccess = false
.Najlepszym rozwiązaniem jest użycie
ReachabilitySwift
klasy , napisówSwift 2
i zastosowańSCNetworkReachabilityRef
.Proste i łatwe:
Działa jak urok.
Cieszyć się
źródło
SCNetworkReachability
klasy w Swift, jest to sugestia zależności, której należy użyć do sprawdzenia prawidłowego połączenia sieciowego.zaktualizował odpowiedź juanjo, aby utworzyć pojedynczą instancję
Stosowanie
źródło
To jest w Swift 4.0
Używam tego frameworka https://github.com/ashleymills/Reachability.swift
i instaluję Pod ..
W AppDelegate
Jeśli nie ma internetu, pojawi się ekran accessabilityViewController
źródło