xcode 在 iOS 中检查 Internet 连接的最佳方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38726100/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 09:06:39  来源:igfitidea点击:

Best Approach For Checking Internet Connection in iOS

iosswiftxcodereachabilityinternet-connection

提问by skJosh

I have been searching through internet to find the best way to check for internet connection in iOS that works for both in IPv4 and IPv6 network environment. I found there are many possible answers but very confused on which one to apply. What I need to do is the following:

我一直在通过互联网搜索以找到在 iOS 中检查适用于 IPv4 和 IPv6 网络环境的互联网连接的最佳方法。我发现有很多可能的答案,但对应用哪一个很困惑。我需要做的是以下内容:

   // Check for internet connection

if (internetConnectionIsAvailable) {
   // make rest calls
}else
   // show cached data
}

I found the following options that are suggested in internet.

我在互联网上找到了以下建议的选项。

OPTION 1:Use apple Reachability class

选项 1:使用苹果 Reachability 类

With Reachability I can check internet connectivity as following which is short and direct, and don't have to wait for any response.

使用 Reachability,我可以按以下方式检查互联网连接,这是简短而直接的,无需等待任何响应。

 - (BOOL)connected
    {
        Reachability *reachability = [Reachability reachabilityForInternetConnection];
        NetworkStatus networkStatus = [reachability currentReachabilityStatus];
        return !(networkStatus == NotReachable);
    }

- (void)viewDidLoad {
    [super viewDidLoad];

    if (![self connected]){
     // Not connected
    }else{
    // Connected
    }

}

But here internet checking is done at pre-flight, which is against suggestion by apple engineer as seen on WWDC video. Also if you check ReadMe.md, it has been mentioned that Reachability fully supports IPv6. But if method reachabilityForInternetConnectionis checked in Reachability.m they have used sockaddr_in, sockaddr_in6 has not been used which is recommended for IPv6 network. So I don't know if it will work in IPv6 network.

但是这里互联网检查是在飞行前完成的,这与苹果工程师在WWDC 视频中看到的建议相悖。此外,如果您查看 ReadMe.md,就会提到 Reachability 完全支持 IPv6。但是如果在 Reachability.m 中检查了方法reachabilityForInternetConnection,他们已经使用了 sockaddr_in,sockaddr_in6 还没有被使用,推荐用于 IPv6 网络。所以我不知道它是否可以在 IPv6 网络中工作。

OPTION 2: Use Alamofire to connect

选项 2:使用 Alamofire 连接

  • Just try to connect as in one of stackoverflow answer. The code also shown below:-

    Alamofire.request(.GET,"http://superrandomdomainnamethatisnotused.com/superrandompath").responseString {
        (request, response, stringData, error) in
    
        if let networkError = error {
            if (networkError.code == -1009) {
                println("No Internet \(error)")
            }
        }
    }
    
  • 只需尝试按照stackoverflow answer之一进行连接。代码还显示如下:-

    Alamofire.request(.GET,"http://superrandomdomainnamethatisnotused.com/superrandompath").responseString {
        (request, response, stringData, error) in
    
        if let networkError = error {
            if (networkError.code == -1009) {
                println("No Internet \(error)")
            }
        }
    }
    

But isn't it time consuming to try to connect to some host, wait for the response and then know if online/offline.

但是尝试连接到某个主机,等待响应然后知道是否在线/离线不是很耗时。

OPTION 3:Use Tony Million's version of Reachability. But the author has warned of app being rejected while using this. I can use this as code shown below:-

选项 3:使用 Tony Million 的Reachability版本。但是作者警告说,在使用此应用程序时会被拒绝。我可以将其用作如下所示的代码:-

// Checks if we have an internet connection or not
- (void)testInternetConnection
{   
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"There in internet connection");
        });
    };

    // Internet is not reachable
    internetReachableFoo.unreachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Someone broke the internet :(");
        });
    };

    [internetReachableFoo startNotifier];
}

But in this option, my question is, is this right approach to test internet by connecting http://google.com. Does this guarantee 100% results? What if google is down? If the app is used in country where google.com is not allowed whats the result?

但在这个选项中,我的问题是,这是通过连接http://google.com来测试互联网的正确方法。这能保证 100% 结果吗?如果谷歌宕机了怎么办?如果该应用程序在不允许 google.com 的国家/地区使用,结果是什么?

So I have been in a big dilemma which option to choose, if these options are the right way or is there a better way of checking internet which guarantee 100% results and works in both IPv4 and IPv6 network. Can anyone suggest me which option is better or should I go for other approach, what is the better way to accomplish this.

所以我一直处于一个很大的困境中选择哪个选项,如果这些选项是正确的方法,或者是否有更好的方法来检查互联网,保证 100% 结果并在 IPv4 和 IPv6 网络中工作。任何人都可以建议我哪个选项更好,或者我应该采用其他方法,实现这一目标的更好方法是什么。

Your reply will be much appreciated.

您的回复将不胜感激。

回答by emraz

For Swift 3, Xcode 8......

对于 Swift 3、Xcode 8......

func isInternetAvailable() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
    zeroAddress.sin_family = sa_family_t(AF_INET)

    guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
        
import SystemConfiguration

class Reachability {

    class func isConnectedToNetwork() -> 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)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
            SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer(
if Reachability.isConnectedToNetwork() {
    //do something
}
)) } var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0) if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false { return false } let isReachable = flags == .Reachable let needsConnection = flags == .ConnectionRequired return isReachable && !needsConnection } }
.withMemoryRebound(to: sockaddr.self, capacity: 1) { SCNetworkReachabilityCreateWithAddress(nil,
#import Alamofire

class MNNetworkUtils {
  static let main = MNNetworkUtils()
  init() {
    manager = NetworkReachabilityManager(host: "google.com")
    listenForReachability()
  }

  private let manager: NetworkReachabilityManager?
  private var reachable: Bool = false
  private func listenForReachability() {
    self.manager?.listener = { [unowned self] status in
      switch status {
      case .notReachable:
        self.reachable = false
      case .reachable(_), .unknown:
        self.reachable = true
      }
    }
    self.manager?.startListening()
  }

  func isConnected() -> Bool {
    return reachable
  }
}
) } }) 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) }

回答by nuynait

Alamofire

阿拉莫火

If you are already using Alamofirefor all the RESTful Api, here is what you can benifit from that.

如果您已经将Alamofire用于所有 RESTful Api,那么您可以从中受益

You can add following class to your app, and call MNNetworkUtils.main.isConnected()to get a boolean on whether its connected or not.

您可以将以下类添加到您的应用程序,并调用MNNetworkUtils.main.isConnected()以获取有关其是否已连接的布尔值。

##代码##

This is a singleton class. Every time, when user connect or disconnect the network, it will override self.reachableto true/false correctly, because we start listening for the NetworkReachabilityManageron singleton initialization.

这是一个单例类。每次当用户连接或断开网络时,它都会self.reachable正确地覆盖为 true/false,因为我们开始监听NetworkReachabilityManageron singleton 初始化。

Also in order to monitor reachability, you need to provide a host, currently I am using google.comfeel free to change to any other hosts or one of yours if needed.

此外,为了监控可达性,您需要提供一个主机,目前我正在使用,如果需要,可以google.com随意更改为任何其他主机或您的主机。

For best approach, I think if you are already using Alamofirethis can be the best approach. I don't think monitoring google.comis a bad design. Feel free to correct me if I'm wrong.

对于最佳方法,我认为如果您已经在使用Alamofire,这可能是最佳方法。我不认为监控google.com是一个糟糕的设计。如果我错了,请随时纠正我。