重庆迈尖科技有限公司
2018-08-14 3e67eb3d9b87c159ccd1be9c1c55a562341dfe8d
Merge branch 'master' of ssh://193.112.35.168:29418/haicaojie into JUN

# Conflicts:
# MIduo.xcworkspace/xcuserdata/mj.xcuserdatad/UserInterfaceState.xcuserstate
16个文件已修改
8个文件已添加
2085 ■■■■■ 已修改文件
MIduo.xcodeproj/project.pbxproj 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo.xcworkspace/xcuserdata/mj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/Reachability.h 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/Reachability.m 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SGNetObserver.h 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SGNetObserver.m 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SimplePing.h 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SimplePing.m 785 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SimplePinger.h 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/lib/SGNetObserver/SimplePinger.m 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/优惠券/推荐/RecommendCouponViewController.m 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/LoginViewController.m 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/SJUnbindPhoneViewController.m 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/balance/体现/AddIncarnateViewController.m 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/balance/体现/AddIncarnateViewController.xib 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/balance/明细/BalaDetailViewController.m 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/collection/MinCollectViewController.m 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/message/MineMessageViewController.m 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/messageLogin/MessageLoginViewController.m 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/userInfoViewController.m 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/网页视图/OrderViewController.m 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/网页视图/商品详情/GoodDeTrViewController.m 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/邀请/商品分享/ShonpingShareViewController.m 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/首页/ListViewController.m 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo.xcodeproj/project.pbxproj
@@ -491,10 +491,6 @@
        2D0DF78D20C642AE002BB619 /* SJUnbindPhoneViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2D0DF78B20C642AE002BB619 /* SJUnbindPhoneViewController.xib */; };
        2D0E729620C0DAE600822DC8 /* SJButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D0E729520C0DAE600822DC8 /* SJButton.m */; };
        2D0F7DB620D0F91600355B51 /* SJTransitionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D0F7DB520D0F91600355B51 /* SJTransitionView.m */; };
        2D100B63212159D000109DAF /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D100B5C212159CF00109DAF /* Reachability.m */; };
        2D100B64212159D000109DAF /* SGNetObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D100B5E212159CF00109DAF /* SGNetObserver.m */; };
        2D100B65212159D000109DAF /* SimplePing.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D100B60212159CF00109DAF /* SimplePing.m */; };
        2D100B66212159D000109DAF /* SimplePinger.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D100B62212159CF00109DAF /* SimplePinger.m */; };
        2D10FAC32108613500C4C3E0 /* WXBindTipsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D10FAC22108613500C4C3E0 /* WXBindTipsView.m */; };
        2D1175B121199F4000D4CD0F /* ObtainProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1175AB21199F3F00D4CD0F /* ObtainProperty.m */; };
        2D1175B221199F4000D4CD0F /* PlistFileOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1175AC21199F3F00D4CD0F /* PlistFileOperator.m */; };
@@ -543,6 +539,10 @@
        2DEAE78220EC6748003349B4 /* SJNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEAE78120EC6748003349B4 /* SJNetwork.m */; };
        2DEF568120FF20990071C985 /* SJTipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEF568020FF20990071C985 /* SJTipView.m */; };
        2DEF568420FF36620071C985 /* SJBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEF568320FF36620071C985 /* SJBaseViewController.m */; };
        2DFBA9CD21217D6F00AB845B /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DFBA9C621217D6F00AB845B /* Reachability.m */; };
        2DFBA9CE21217D6F00AB845B /* SGNetObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DFBA9C821217D6F00AB845B /* SGNetObserver.m */; };
        2DFBA9CF21217D6F00AB845B /* SimplePing.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DFBA9CA21217D6F00AB845B /* SimplePing.m */; };
        2DFBA9D021217D6F00AB845B /* SimplePinger.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DFBA9CC21217D6F00AB845B /* SimplePinger.m */; };
        2DFC813A20E09D4500CCDAB7 /* yw_1222.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2DFC813920E09D4500CCDAB7 /* yw_1222.jpg */; };
        AD52310E1F1B6A24007FCFA1 /* OrderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD52310D1F1B6A24007FCFA1 /* OrderViewController.m */; };
/* End PBXBuildFile section */
@@ -1456,14 +1456,6 @@
        2D0E729520C0DAE600822DC8 /* SJButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJButton.m; sourceTree = "<group>"; };
        2D0F7DB420D0F91600355B51 /* SJTransitionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJTransitionView.h; sourceTree = "<group>"; };
        2D0F7DB520D0F91600355B51 /* SJTransitionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJTransitionView.m; sourceTree = "<group>"; };
        2D100B5B212159CF00109DAF /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
        2D100B5C212159CF00109DAF /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
        2D100B5D212159CF00109DAF /* SGNetObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGNetObserver.h; sourceTree = "<group>"; };
        2D100B5E212159CF00109DAF /* SGNetObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGNetObserver.m; sourceTree = "<group>"; };
        2D100B5F212159CF00109DAF /* SimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePing.h; sourceTree = "<group>"; };
        2D100B60212159CF00109DAF /* SimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePing.m; sourceTree = "<group>"; };
        2D100B61212159CF00109DAF /* SimplePinger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePinger.h; sourceTree = "<group>"; };
        2D100B62212159CF00109DAF /* SimplePinger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePinger.m; sourceTree = "<group>"; };
        2D10FAC12108613500C4C3E0 /* WXBindTipsView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXBindTipsView.h; sourceTree = "<group>"; };
        2D10FAC22108613500C4C3E0 /* WXBindTipsView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXBindTipsView.m; sourceTree = "<group>"; };
        2D1175AB21199F3F00D4CD0F /* ObtainProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObtainProperty.m; sourceTree = "<group>"; };
@@ -1544,6 +1536,14 @@
        2DEF568020FF20990071C985 /* SJTipView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJTipView.m; sourceTree = "<group>"; };
        2DEF568220FF36620071C985 /* SJBaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJBaseViewController.h; sourceTree = "<group>"; };
        2DEF568320FF36620071C985 /* SJBaseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJBaseViewController.m; sourceTree = "<group>"; };
        2DFBA9C521217D6F00AB845B /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
        2DFBA9C621217D6F00AB845B /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
        2DFBA9C721217D6F00AB845B /* SGNetObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGNetObserver.h; sourceTree = "<group>"; };
        2DFBA9C821217D6F00AB845B /* SGNetObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGNetObserver.m; sourceTree = "<group>"; };
        2DFBA9C921217D6F00AB845B /* SimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePing.h; sourceTree = "<group>"; };
        2DFBA9CA21217D6F00AB845B /* SimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePing.m; sourceTree = "<group>"; };
        2DFBA9CB21217D6F00AB845B /* SimplePinger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePinger.h; sourceTree = "<group>"; };
        2DFBA9CC21217D6F00AB845B /* SimplePinger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePinger.m; sourceTree = "<group>"; };
        2DFC813920E09D4500CCDAB7 /* yw_1222.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = yw_1222.jpg; sourceTree = "<group>"; };
        A10E40577F379E83D85926C6 /* Pods_MIduo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MIduo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
        AB238CE26A4E87752975FA82 /* Pods-MIduo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MIduo.release.xcconfig"; path = "Pods/Target Support Files/Pods-MIduo/Pods-MIduo.release.xcconfig"; sourceTree = "<group>"; };
@@ -3238,7 +3238,7 @@
        18AC538B1E5A9876006D1FDF /* lib */ = {
            isa = PBXGroup;
            children = (
                2D100B5A212159CF00109DAF /* SGNetObserver */,
                2DFBA9C421217D6F00AB845B /* SGNetObserver */,
                2D1175AA21199F2700D4CD0F /* FileManger */,
                2D9F157B2117E8E800EFFAFB /* EasyJSWebView-master */,
                1845C239209C562C009C639B /* LBXScan */,
@@ -3454,22 +3454,6 @@
            path = balance;
            sourceTree = "<group>";
        };
        2D100B5A212159CF00109DAF /* SGNetObserver */ = {
            isa = PBXGroup;
            children = (
                2D100B5B212159CF00109DAF /* Reachability.h */,
                2D100B5C212159CF00109DAF /* Reachability.m */,
                2D100B5D212159CF00109DAF /* SGNetObserver.h */,
                2D100B5E212159CF00109DAF /* SGNetObserver.m */,
                2D100B5F212159CF00109DAF /* SimplePing.h */,
                2D100B60212159CF00109DAF /* SimplePing.m */,
                2D100B61212159CF00109DAF /* SimplePinger.h */,
                2D100B62212159CF00109DAF /* SimplePinger.m */,
            );
            name = SGNetObserver;
            path = "../../../../SGNetObserver-master/SGNetObserver";
            sourceTree = "<group>";
        };
        2D1175AA21199F2700D4CD0F /* FileManger */ = {
            isa = PBXGroup;
            children = (
@@ -3514,6 +3498,21 @@
                2D9F15862117E8E800EFFAFB /* test.html */,
            );
            path = "EasyJSWebView-master";
            sourceTree = "<group>";
        };
        2DFBA9C421217D6F00AB845B /* SGNetObserver */ = {
            isa = PBXGroup;
            children = (
                2DFBA9C521217D6F00AB845B /* Reachability.h */,
                2DFBA9C621217D6F00AB845B /* Reachability.m */,
                2DFBA9C721217D6F00AB845B /* SGNetObserver.h */,
                2DFBA9C821217D6F00AB845B /* SGNetObserver.m */,
                2DFBA9C921217D6F00AB845B /* SimplePing.h */,
                2DFBA9CA21217D6F00AB845B /* SimplePing.m */,
                2DFBA9CB21217D6F00AB845B /* SimplePinger.h */,
                2DFBA9CC21217D6F00AB845B /* SimplePinger.m */,
            );
            path = SGNetObserver;
            sourceTree = "<group>";
        };
        3EB2FCBC06FCFF59022C5ECD /* Frameworks */ = {
@@ -3933,7 +3932,7 @@
                1845C450209C562D009C639B /* ZXAddressBookDoCoMoResultParser.m in Sources */,
                1865E43C1EF1112A00333767 /* SectionTopicCollectionViewCell.m in Sources */,
                1845C4C1209C562E009C639B /* ZXRSSExpandedDecodedNumeric.m in Sources */,
                2D100B64212159D000109DAF /* SGNetObserver.m in Sources */,
                2DFBA9CE21217D6F00AB845B /* SGNetObserver.m in Sources */,
                181ECE271EF369BF00472224 /* ZJSegmentStyle.m in Sources */,
                1892034720BE51C6008C1045 /* LBXZXCapture.m in Sources */,
                1845C45A209C562D009C639B /* ZXGeoParsedResult.m in Sources */,
@@ -3949,7 +3948,7 @@
                1897D9C01E600E94003DF6FE /* ClearCollectionReusableView.m in Sources */,
                2D9F158A2117E8E800EFFAFB /* EasyJSWebViewProxyDelegate.m in Sources */,
                1845C4BE209C562E009C639B /* ZXRSSExpandedCurrentParsingState.m in Sources */,
                2D100B65212159D000109DAF /* SimplePing.m in Sources */,
                2DFBA9CF21217D6F00AB845B /* SimplePing.m in Sources */,
                187522901E654D6900B6AE15 /* SureWebViewController.m in Sources */,
                18D399AD1EA765AD00A01CD3 /* thirdClassificationViewController.m in Sources */,
                1845C514209C562E009C639B /* ZXQRCodeEncoder.m in Sources */,
@@ -4002,7 +4001,7 @@
                182BEB601EAA081400B11FC5 /* LXAlertView.m in Sources */,
                1810FBF91E7FBDBB005B42B3 /* NSString+Utils.m in Sources */,
                1892034320BE51C6008C1045 /* LBXScanView.m in Sources */,
                2D100B63212159D000109DAF /* Reachability.m in Sources */,
                2DFBA9CD21217D6F00AB845B /* Reachability.m in Sources */,
                2D43E74E211D92790008BA48 /* ALAnomalyNetWorkView.m in Sources */,
                2D6858F420DB5D8B00E4376A /* SJCouponCollectionViewCell.m in Sources */,
                1845C47D209C562D009C639B /* ZXBitMatrix.m in Sources */,
@@ -4057,7 +4056,7 @@
                1896F26D1FD0ED96009D6EEF /* RecommendCouponViewController.m in Sources */,
                18D9541A20AE705C005D5D02 /* FeignGoodsDetaiViewController.m in Sources */,
                1845C4A1209C562E009C639B /* ZXDataMatrixDefaultPlacement.m in Sources */,
                2D100B66212159D000109DAF /* SimplePinger.m in Sources */,
                2DFBA9D021217D6F00AB845B /* SimplePinger.m in Sources */,
                1845C4B2209C562E009C639B /* ZXAbstractExpandedDecoder.m in Sources */,
                1845C4D6209C562E009C639B /* ZXEAN13Reader.m in Sources */,
                1845C4B4209C562E009C639B /* ZXAI01320xDecoder.m in Sources */,
MIduo.xcworkspace/xcuserdata/mj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -103,7 +103,7 @@
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "261"
            endingLineNumber = "261"
            landmarkName = "-dealloc"
            landmarkName = "-networkError:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
MIduo/Êý¾Ý/lib/SGNetObserver/Reachability.h
New file
@@ -0,0 +1,68 @@
/*
 Copyright (C) 2016 Apple Inc. All Rights Reserved.
 See LICENSE.txt for this sample’s licensing information
 Abstract:
 Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
 */
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
typedef enum : NSInteger {
    NotReachable = 0,
    ReachableViaWiFi,
    ReachableViaWWAN
} NetworkStatus;
#pragma mark IPv6 Support
//Reachability fully support IPv6.  For full details, see ReadMe.md.
@interface Reachability : NSObject
/**
 *  å›žè°ƒ
 */
@property (nonatomic,copy) void(^networkStatusDidChanged)();
/**
 *  hostname
 */
@property (nonatomic,copy,readonly)NSString *hostName;
/*!
 * Use to check the reachability of a given host name.
 */
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
/*!
 * Use to check the reachability of a given IP address.
 */
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
/*!
 * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
 */
+ (instancetype)reachabilityForInternetConnection;
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi;
/*!
 * Start listening for reachability notifications on the current run loop.
 */
- (BOOL)startNotifier;
- (void)stopNotifier;
- (NetworkStatus)currentReachabilityStatus;
/*!
 * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
 */
- (BOOL)connectionRequired;
@end
MIduo/Êý¾Ý/lib/SGNetObserver/Reachability.m
New file
@@ -0,0 +1,247 @@
/*
 Copyright (C) 2016 Apple Inc. All Rights Reserved.
 See LICENSE.txt for this sample’s licensing information
 Abstract:
 Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
 */
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <CoreFoundation/CoreFoundation.h>
#import "Reachability.h"
#pragma mark IPv6 Support
//Reachability fully support IPv6.  For full details, see ReadMe.md.
#pragma mark - Supporting functions
#define kShouldPrintReachabilityFlags 1
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
    NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
          (flags & kSCNetworkReachabilityFlagsIsWWAN)                ? 'W' : '-',
          (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
          (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
          (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
          (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
          (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
          (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
          (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
          (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
          comment
          );
#endif
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
    NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
    NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
    Reachability *hostReachability = (__bridge Reachability *)info;
    if (hostReachability.networkStatusDidChanged) {
        hostReachability.networkStatusDidChanged();
    }
}
#pragma mark - Reachability implementation
@interface Reachability()
@end
@implementation Reachability
{
    SCNetworkReachabilityRef _reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
    Reachability* returnValue = NULL;
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
    if (reachability != NULL)
    {
        returnValue= [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
        }
        else {
            CFRelease(reachability);
        }
    }
    returnValue->_hostName = hostName;
    return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
    Reachability* returnValue = NULL;
    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
        }
        else {
            CFRelease(reachability);
        }
    }
    return returnValue;
}
+ (instancetype)reachabilityForInternetConnection
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi
#pragma mark - Start and stop notifier
- (BOOL)startNotifier
{
    BOOL returnValue = NO;
    SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
    if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
    {
        if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
        {
            returnValue = YES;
        }
    }
    return returnValue;
}
- (void)stopNotifier
{
    if (_reachabilityRef != NULL)
    {
        SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    }
}
- (void)dealloc
{
    [self stopNotifier];
    if (_reachabilityRef != NULL)
    {
        CFRelease(_reachabilityRef);
    }
}
#pragma mark - Network Flag Handling
- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
    PrintReachabilityFlags(flags, "networkStatusForFlags");
    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
    {
        // The target host is not reachable.
        return NotReachable;
    }
    NetworkStatus returnValue = NotReachable;
    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        /*
         If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
         */
        returnValue = ReachableViaWiFi;
    }
    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
    {
        /*
         ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
         */
        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
        {
            /*
             ... and no [user] intervention is needed...
             */
            returnValue = ReachableViaWiFi;
        }
    }
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        /*
         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
         */
        returnValue = ReachableViaWWAN;
    }
    return returnValue;
}
- (BOOL)connectionRequired
{
    NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
    SCNetworkReachabilityFlags flags;
    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
    }
    return NO;
}
- (NetworkStatus)currentReachabilityStatus
{
    NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
    NetworkStatus returnValue = NotReachable;
    SCNetworkReachabilityFlags flags;
    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        returnValue = [self networkStatusForFlags:flags];
    }
    return returnValue;
}
@end
MIduo/Êý¾Ý/lib/SGNetObserver/SGNetObserver.h
New file
@@ -0,0 +1,84 @@
//
//  SGNetObserver.h
//  SGNetObserverDemo
//
//  Created by apple on 16/9/19.
//  Copyright Â© 2016å¹´ iOSSinger. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
 *  ç½‘络状态变化的全局通知
 *  info-keys:
 *  @"status"  ç½‘络状态,SGNetworkStatus类型
 *  @"host"    host åœ°å€
 */
extern NSString *SGReachabilityChangedNotification;
typedef NS_ENUM(NSUInteger, SGNetworkStatus) {
    SGNetworkStatusNone,
    SGNetworkStatus3G,
    SGNetworkStatus4G,
    SGNetworkStatusWifi,
    SGNetworkStatusUkonow
};
@protocol SGNetworkStatusDelegate <NSObject>
- (void)observer:(id)obsever host:(NSString *)host networkStatusDidChanged:(SGNetworkStatus)ststus;
@end
@interface SGNetObserver : NSObject
/**
 *  å½“前网络状态
 */
@property (nonatomic,assign) SGNetworkStatus networkStatus;
/**
 * delegate,如果设定,只走代理,不发全局通知.否则只发全局通知
 */
@property (nonatomic,weak) id <SGNetworkStatusDelegate> delegate;
/**
 *  æ˜¯å¦æ”¯æŒIPv4,默认全部支持
 */
@property (nonatomic,assign) BOOL supportIPv4;
/**
 *  æ˜¯å¦æ”¯æŒIPv6
 */
@property (nonatomic,assign) BOOL supportIPv6;
/**
 *  æœ‰å¾ˆå°æ¦‚率ping失败(实际没有断网),设定多少次ping失败认为是断网,默认2次
 */
@property (nonatomic,assign) NSUInteger failureTimes;
/**
 *  ping çš„频率,默认1s
 */
@property (nonatomic,assign) NSTimeInterval interval;
/**
 *  é»˜è®¤www.baidu.com
 */
+ (instancetype)defultObsever;
/**
 *  è‡ªå®šä¹‰åœ°å€
 */
+ (instancetype)observerWithHost:(NSString *)host;
/**
 *  å¼€å§‹ç›‘控
 */
- (void)startNotifier;
/**
 *  åœæ­¢ç›‘控
 */
- (void)stopNotifier;
@end
MIduo/Êý¾Ý/lib/SGNetObserver/SGNetObserver.m
New file
@@ -0,0 +1,183 @@
//
//  SGNetObserver.m
//  SGNetObserverDemo
//
//  Created by apple on 16/9/19.
//  Copyright Â© 2016å¹´ iOSSinger. All rights reserved.
//
#import "SGNetObserver.h"
#import "Reachability.h"
#import "SimplePinger.h"
NSString *SGReachabilityChangedNotification = @"SGNetworkReachabilityChangedNotification";
@interface SGNetObserver()
@property (nonatomic,copy) NSString *host;
@property (nonatomic,strong) Reachability *hostReachability;
@property (nonatomic,strong) SimplePinger *pinger;
@end
@implementation SGNetObserver
#pragma mark - åˆå§‹åŒ–
+ (instancetype)defultObsever{
    SGNetObserver *obsever = [[self alloc] init];
    obsever.host = @"www.baidu.com";
    return obsever;
}
+ (instancetype)observerWithHost:(NSString *)host{
    SGNetObserver *obsever = [[self alloc] init];
    obsever.host = host;
    return obsever;
}
- (instancetype)init{
    if (self = [super init]) {
        _networkStatus = -1;
        _failureTimes = 2;
        _interval = 1.0;
    }
    return self;
}
- (void)dealloc{
    [self.hostReachability stopNotifier];
    [self.pinger stopNotifier];
}
#pragma mark - function
- (void)startNotifier{
    [self.hostReachability startNotifier];
    [self.pinger startNotifier];
}
- (void)stopNotifier{
    [self.hostReachability stopNotifier];
    [self.pinger stopNotifier];
}
#pragma mark - delegate
- (void)networkStatusDidChanged{
    //获取两种方法得到的联网状态,并转为BOOL值
    BOOL status1 = [self.hostReachability currentReachabilityStatus];
    BOOL status2 =  self.pinger.reachable;
    //综合判断网络,判断原则:Reachability -> pinger
    if (status1 && status2) {//有网
        self.networkStatus = self.netWorkDetailStatus;
    }else{//无网
        self.networkStatus = SGNetworkStatusNone;
    }
    if (!status2 && status1) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"networkError" object:nil];
    }
}
#pragma mark - setter
- (void)setNetworkStatus:(SGNetworkStatus)networkStatus{
    if (_networkStatus != networkStatus) {
        _networkStatus = networkStatus;
        NSLog(@"网络状态-----%@",self.networkDict[@(networkStatus)]);
        //有代理
        if(self.delegate){//调用代理
            if ([self.delegate respondsToSelector:@selector(observer:host:networkStatusDidChanged:)]) {
                [self.delegate observer:self host:self.host networkStatusDidChanged:networkStatus];
            }
        }else{//发送全局通知
            NSDictionary *info = @{@"status" : @(networkStatus),
                                   @"host"   : self.host      };
            [[NSNotificationCenter defaultCenter] postNotificationName:SGReachabilityChangedNotification object:nil userInfo:info];
        }
    }
}
#pragma mark - getter
- (Reachability *)hostReachability{
    if (_hostReachability == nil) {
        _hostReachability = [Reachability reachabilityWithHostName:self.host];
        __weak typeof(self) weakSelf = self;
        [_hostReachability setNetworkStatusDidChanged:^{
            [weakSelf networkStatusDidChanged];
        }];
    }
    return _hostReachability;
}
- (SimplePinger *)pinger{
    if (_pinger == nil) {
        _pinger = [SimplePinger simplePingerWithHostName:self.host];
        _pinger.supportIPv4 = self.supportIPv4;
        _pinger.supportIPv6 = self.supportIPv6;
        _pinger.interval = self.interval;
        _pinger.failureTimes = self.failureTimes;
        __weak typeof(self) weakSelf = self;
        [_pinger setNetworkStatusDidChanged:^{
            [weakSelf networkStatusDidChanged];
        }];
    }
    return _pinger;
}
#pragma mark - tools
- (SGNetworkStatus)netWorkDetailStatus{
    UIApplication *app = [UIApplication sharedApplication];
    UIView *statusBar = [app valueForKeyPath:@"statusBar"];
    UIView *foregroundView = [statusBar valueForKeyPath:@"foregroundView"];
    UIView *networkView = nil;
    for (UIView *childView in foregroundView.subviews) {
        if ([childView isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
            networkView = childView;
        }
    }
    SGNetworkStatus status = SGNetworkStatusNone;
    if (networkView) {
        int netType = [[networkView valueForKeyPath:@"dataNetworkType"]intValue];
        switch (netType) {
            case 0:
                status = SGNetworkStatusNone;
                break;
            case 1://实际上是2G
                status = SGNetworkStatusUkonow;
                break;
            case 2:
                status = SGNetworkStatus3G;
                break;
            case 3:
                status = SGNetworkStatus4G;
                break;
            case 5:
                status = SGNetworkStatusWifi;
                break;
            default:
                status = SGNetworkStatusUkonow;
                break;
        }
    }
    return status;
}
- (NSDictionary *)networkDict{
    return @{
             @(SGNetworkStatusNone)   : @"无网络",
             @(SGNetworkStatusUkonow) : @"未知网络",
             @(SGNetworkStatus3G)     : @"3G网络",
             @(SGNetworkStatus4G)     : @"4G网络",
             @(SGNetworkStatusWifi)   : @"WIFI网络",
            };
}
@end
MIduo/Êý¾Ý/lib/SGNetObserver/SimplePing.h
New file
@@ -0,0 +1,272 @@
/*
    Copyright (C) 2016 Apple Inc. All Rights Reserved.
    See LICENSE.txt for this sample’s licensing information
    Abstract:
    An object wrapper around the low-level BSD Sockets ping function.
 */
@import Foundation;
#include <AssertMacros.h>           // for __Check_Compile_Time
NS_ASSUME_NONNULL_BEGIN
@protocol SimplePingDelegate;
/*! Controls the IP address version used by SimplePing instances.
 */
typedef NS_ENUM(NSInteger, SimplePingAddressStyle) {
    SimplePingAddressStyleAny,          ///< Use the first IPv4 or IPv6 address found; the default.
    SimplePingAddressStyleICMPv4,       ///< Use the first IPv4 address found.
    SimplePingAddressStyleICMPv6        ///< Use the first IPv6 address found.
};
/*! An object wrapper around the low-level BSD Sockets ping function.
 *  \details To use the class create an instance, set the delegate and call `-start`
 *      to start the instance on the current run loop.  If things go well you'll soon get the
 *      `-simplePing:didStartWithAddress:` delegate callback.  From there you can can call
 *      `-sendPingWithData:` to send a ping and you'll receive the
 *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:` and
 *      `-simplePing:didReceiveUnexpectedPacket:` delegate callbacks as ICMP packets arrive.
 *
 *      The class can be used from any thread but the use of any single instance must be
 *      confined to a specific thread and that thread must run its run loop.
 */
@interface SimplePing : NSObject
- (instancetype)init NS_UNAVAILABLE;
/*! Initialise the object to ping the specified host.
 *  \param hostName The DNS name of the host to ping; an IPv4 or IPv6 address in string form will
 *      work here.
 *  \returns The initialised object.
 */
- (instancetype)initWithHostName:(NSString *)hostName NS_DESIGNATED_INITIALIZER;
/*! A copy of the value passed to `-initWithHostName:`.
 */
@property (nonatomic, copy, readonly) NSString * hostName;
/*! The delegate for this object.
 *  \details Delegate callbacks are schedule in the default run loop mode of the run loop of the
 *      thread that calls `-start`.
 */
@property (nonatomic, weak, readwrite, nullable) id<SimplePingDelegate> delegate;
/*! Controls the IP address version used by the object.
 *  \details You should set this value before starting the object.
 */
@property (nonatomic, assign, readwrite) SimplePingAddressStyle addressStyle;
/*! The address being pinged.
 *  \details The contents of the NSData is a (struct sockaddr) of some form.  The
 *      value is nil while the object is stopped and remains nil on start until
 *      `-simplePing:didStartWithAddress:` is called.
 */
@property (nonatomic, copy, readonly, nullable) NSData * hostAddress;
/*! The address family for `hostAddress`, or `AF_UNSPEC` if that's nil.
 */
@property (nonatomic, assign, readonly) sa_family_t hostAddressFamily;
/*! The identifier used by pings by this object.
 *  \details When you create an instance of this object it generates a random identifier
 *      that it uses to identify its own pings.
 */
@property (nonatomic, assign, readonly) uint16_t identifier;
/*! The next sequence number to be used by this object.
 *  \details This value starts at zero and increments each time you send a ping (safely
 *      wrapping back to zero if necessary).  The sequence number is included in the ping,
 *      allowing you to match up requests and responses, and thus calculate ping times and
 *      so on.
 */
@property (nonatomic, assign, readonly) uint16_t nextSequenceNumber;
/*! Starts the object.
 *  \details You should set up the delegate and any ping parameters before calling this.
 *
 *      If things go well you'll soon get the `-simplePing:didStartWithAddress:` delegate
 *      callback, at which point you can start sending pings (via `-sendPingWithData:`) and
 *      will start receiving ICMP packets (either ping responses, via the
 *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:` delegate callback, or
 *      unsolicited ICMP packets, via the `-simplePing:didReceiveUnexpectedPacket:` delegate
 *      callback).
 *
 *      If the object fails to start, typically because `hostName` doesn't resolve, you'll get
 *      the `-simplePing:didFailWithError:` delegate callback.
 *
 *      It is not correct to start an already started object.
 */
- (void)start;
/*! Sends a ping packet containing the specified data.
 *  \details Sends an actual ping.
 *
 *      The object must be started when you call this method and, on starting the object, you must
 *      wait for the `-simplePing:didStartWithAddress:` delegate callback before calling it.
 *  \param data Some data to include in the ping packet, after the ICMP header, or nil if you
 *      want the packet to include a standard 56 byte payload (resulting in a standard 64 byte
 *      ping).
 */
- (void)sendPingWithData:(nullable NSData *)data;
/*! Stops the object.
 *  \details You should call this when you're done pinging.
 *
 *      It's safe to call this on an object that's stopped.
 */
- (void)stop;
@end
/*! A delegate protocol for the SimplePing class.
 */
@protocol SimplePingDelegate <NSObject>
@optional
/*! A SimplePing delegate callback, called once the object has started up.
 *  \details This is called shortly after you start the object to tell you that the
 *      object has successfully started.  On receiving this callback, you can call
 *      `-sendPingWithData:` to send pings.
 *
 *      If the object didn't start, `-simplePing:didFailWithError:` is called instead.
 *  \param pinger The object issuing the callback.
 *  \param address The address that's being pinged; at the time this delegate callback
 *      is made, this will have the same value as the `hostAddress` property.
 */
- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address;
/*! A SimplePing delegate callback, called if the object fails to start up.
 *  \details This is called shortly after you start the object to tell you that the
 *      object has failed to start.  The most likely cause of failure is a problem
 *      resolving `hostName`.
 *
 *      By the time this callback is called, the object has stopped (that is, you don't
 *      need to call `-stop` yourself).
 *  \param pinger The object issuing the callback.
 *  \param error Describes the failure.
 */
- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error;
/*! A SimplePing delegate callback, called when the object has successfully sent a ping packet.
 *  \details Each call to `-sendPingWithData:` will result in either a
 *      `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a
 *      `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you
 *      stop the object before you get the callback).  These callbacks are currently delivered
 *      synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not
 *      considered API.
 *  \param pinger The object issuing the callback.
 *  \param packet The packet that was sent; this includes the ICMP header (`ICMPHeader`) and the
 *      data you passed to `-sendPingWithData:` but does not include any IP-level headers.
 *  \param sequenceNumber The ICMP sequence number of that packet.
 */
- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber;
/*! A SimplePing delegate callback, called when the object fails to send a ping packet.
 *  \details Each call to `-sendPingWithData:` will result in either a
 *      `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a
 *      `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you
 *      stop the object before you get the callback).  These callbacks are currently delivered
 *      synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not
 *      considered API.
 *  \param pinger The object issuing the callback.
 *  \param packet The packet that was not sent; see `-simplePing:didSendPacket:sequenceNumber:`
 *      for details.
 *  \param sequenceNumber The ICMP sequence number of that packet.
 *  \param error Describes the failure.
 */
- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error;
/*! A SimplePing delegate callback, called when the object receives a ping response.
 *  \details If the object receives an ping response that matches a ping request that it
 *      sent, it informs the delegate via this callback.  Matching is primarily done based on
 *      the ICMP identifier, although other criteria are used as well.
 *  \param pinger The object issuing the callback.
 *  \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that
 *      follows that in the ICMP message but does not include any IP-level headers.
 *  \param sequenceNumber The ICMP sequence number of that packet.
 */
- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber;
/*! A SimplePing delegate callback, called when the object receives an unmatched ICMP message.
 *  \details If the object receives an ICMP message that does not match a ping request that it
 *      sent, it informs the delegate via this callback.  The nature of ICMP handling in a
 *      BSD kernel makes this a common event because, when an ICMP message arrives, it is
 *      delivered to all ICMP sockets.
 *
 *      IMPORTANT: This callback is especially common when using IPv6 because IPv6 uses ICMP
 *      for important network management functions.  For example, IPv6 routers periodically
 *      send out Router Advertisement (RA) packets via Neighbor Discovery Protocol (NDP), which
 *      is implemented on top of ICMP.
 *
 *      For more on matching, see the discussion associated with
 *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:`.
 *  \param pinger The object issuing the callback.
 *  \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that
 *      follows that in the ICMP message but does not include any IP-level headers.
 */
- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet;
@end
#pragma mark * ICMP On-The-Wire Format
/*! Describes the on-the-wire header format for an ICMP ping.
 *  \details This defines the header structure of ping packets on the wire.  Both IPv4 and
 *      IPv6 use the same basic structure.
 *
 *      This is declared in the header because clients of SimplePing might want to use
 *      it parse received ping packets.
 */
struct ICMPHeader {
    uint8_t     type;
    uint8_t     code;
    uint16_t    checksum;
    uint16_t    identifier;
    uint16_t    sequenceNumber;
    // data...
};
typedef struct ICMPHeader ICMPHeader;
__Check_Compile_Time(sizeof(ICMPHeader) == 8);
__Check_Compile_Time(offsetof(ICMPHeader, type) == 0);
__Check_Compile_Time(offsetof(ICMPHeader, code) == 1);
__Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2);
__Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4);
__Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6);
enum {
    ICMPv4TypeEchoRequest = 8,          ///< The ICMP `type` for a ping request; in this case `code` is always 0.
    ICMPv4TypeEchoReply   = 0           ///< The ICMP `type` for a ping response; in this case `code` is always 0.
};
enum {
    ICMPv6TypeEchoRequest = 128,        ///< The ICMP `type` for a ping request; in this case `code` is always 0.
    ICMPv6TypeEchoReply   = 129         ///< The ICMP `type` for a ping response; in this case `code` is always 0.
};
NS_ASSUME_NONNULL_END
MIduo/Êý¾Ý/lib/SGNetObserver/SimplePing.m
New file
@@ -0,0 +1,785 @@
/*
    Copyright (C) 2016 Apple Inc. All Rights Reserved.
    See LICENSE.txt for this sample’s licensing information
    Abstract:
    An object wrapper around the low-level BSD Sockets ping function.
 */
#import "SimplePing.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#pragma mark * IPv4 and ICMPv4 On-The-Wire Format
/*! Describes the on-the-wire header format for an IPv4 packet.
 *  \details This defines the header structure of IPv4 packets on the wire.  We need
 *      this in order to skip this header in the IPv4 case, where the kernel passes
 *      it to us for no obvious reason.
 */
struct IPv4Header {
    uint8_t     versionAndHeaderLength;
    uint8_t     differentiatedServices;
    uint16_t    totalLength;
    uint16_t    identification;
    uint16_t    flagsAndFragmentOffset;
    uint8_t     timeToLive;
    uint8_t     protocol;
    uint16_t    headerChecksum;
    uint8_t     sourceAddress[4];
    uint8_t     destinationAddress[4];
    // options...
    // data...
};
typedef struct IPv4Header IPv4Header;
__Check_Compile_Time(sizeof(IPv4Header) == 20);
__Check_Compile_Time(offsetof(IPv4Header, versionAndHeaderLength) == 0);
__Check_Compile_Time(offsetof(IPv4Header, differentiatedServices) == 1);
__Check_Compile_Time(offsetof(IPv4Header, totalLength) == 2);
__Check_Compile_Time(offsetof(IPv4Header, identification) == 4);
__Check_Compile_Time(offsetof(IPv4Header, flagsAndFragmentOffset) == 6);
__Check_Compile_Time(offsetof(IPv4Header, timeToLive) == 8);
__Check_Compile_Time(offsetof(IPv4Header, protocol) == 9);
__Check_Compile_Time(offsetof(IPv4Header, headerChecksum) == 10);
__Check_Compile_Time(offsetof(IPv4Header, sourceAddress) == 12);
__Check_Compile_Time(offsetof(IPv4Header, destinationAddress) == 16);
/*! Calculates an IP checksum.
 *  \details This is the standard BSD checksum code, modified to use modern types.
 *  \param buffer A pointer to the data to checksum.
 *  \param bufferLen The length of that data.
 *  \returns The checksum value, in network byte order.
 */
static uint16_t in_cksum(const void *buffer, size_t bufferLen) {
    //
    size_t              bytesLeft;
    int32_t             sum;
    const uint16_t *    cursor;
    union {
        uint16_t        us;
        uint8_t         uc[2];
    } last;
    uint16_t            answer;
    bytesLeft = bufferLen;
    sum = 0;
    cursor = buffer;
    /*
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
     * sequential 16 bit words to it, and at the end, fold back all the
     * carry bits from the top 16 bits into the lower 16 bits.
     */
    while (bytesLeft > 1) {
        sum += *cursor;
        cursor += 1;
        bytesLeft -= 2;
    }
    /* mop up an odd byte, if necessary */
    if (bytesLeft == 1) {
        last.uc[0] = * (const uint8_t *) cursor;
        last.uc[1] = 0;
        sum += last.us;
    }
    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
    sum += (sum >> 16);            /* add carry */
    answer = (uint16_t) ~sum;   /* truncate to 16 bits */
    return answer;
}
#pragma mark * SimplePing
@interface SimplePing ()
// read/write versions of public properties
@property (nonatomic, copy,   readwrite, nullable) NSData *     hostAddress;
@property (nonatomic, assign, readwrite          ) uint16_t     nextSequenceNumber;
// private properties
/*! True if nextSequenceNumber has wrapped from 65535 to 0.
 */
@property (nonatomic, assign, readwrite)           BOOL         nextSequenceNumberHasWrapped;
/*! A host object for name-to-address resolution.
 */
@property (nonatomic, strong, readwrite, nullable) CFHostRef host __attribute__ ((NSObject));
/*! A socket object for ICMP send and receive.
 */
@property (nonatomic, strong, readwrite, nullable) CFSocketRef socket __attribute__ ((NSObject));
@end
@implementation SimplePing
- (instancetype)initWithHostName:(NSString *)hostName {
    NSParameterAssert(hostName != nil);
    self = [super init];
    if (self != nil) {
        self->_hostName   = [hostName copy];
        self->_identifier = (uint16_t) arc4random();
    }
    return self;
}
- (void)dealloc {
    [self stop];
    // Double check that -stop took care of _host and _socket.
    assert(self->_host == NULL);
    assert(self->_socket == NULL);
}
- (sa_family_t)hostAddressFamily {
    sa_family_t     result;
    result = AF_UNSPEC;
    if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) {
        result = ((const struct sockaddr *) self.hostAddress.bytes)->sa_family;
    }
    return result;
}
/*! Shuts down the pinger object and tell the delegate about the error.
 *  \param error Describes the failure.
 */
- (void)didFailWithError:(NSError *)error {
    id<SimplePingDelegate>  strongDelegate;
    assert(error != nil);
    // We retain ourselves temporarily because it's common for the delegate method
    // to release its last reference to us, which causes -dealloc to be called here.
    // If we then reference self on the return path, things go badly.  I don't think
    // that happens currently, but I've got into the habit of doing this as a
    // defensive measure.
    CFAutorelease( CFBridgingRetain( self ));
    [self stop];
    strongDelegate = self.delegate;
    if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailWithError:)] ) {
        [strongDelegate simplePing:self didFailWithError:error];
    }
}
/*! Shuts down the pinger object and tell the delegate about the error.
 *  \details This converts the CFStreamError to an NSError and then call through to
 *      -didFailWithError: to do the real work.
 *  \param streamError Describes the failure.
 */
- (void)didFailWithHostStreamError:(CFStreamError)streamError {
    NSDictionary *  userInfo;
    NSError *       error;
    if (streamError.domain == kCFStreamErrorDomainNetDB) {
        userInfo = @{(id) kCFGetAddrInfoFailureKey: @(streamError.error)};
    } else {
        userInfo = nil;
    }
    error = [NSError errorWithDomain:(NSString *) kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo];
    [self didFailWithError:error];
}
/*! Builds a ping packet from the supplied parameters.
 *  \param type The packet type, which is different for IPv4 and IPv6.
 *  \param payload Data to place after the ICMP header.
 *  \param requiresChecksum Determines whether a checksum is calculated (IPv4) or not (IPv6).
 *  \returns A ping packet suitable to be passed to the kernel.
 */
- (NSData *)pingPacketWithType:(uint8_t)type payload:(NSData *)payload requiresChecksum:(BOOL)requiresChecksum {
    NSMutableData *         packet;
    ICMPHeader *            icmpPtr;
    packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + payload.length];
    assert(packet != nil);
    icmpPtr = packet.mutableBytes;
    icmpPtr->type = type;
    icmpPtr->code = 0;
    icmpPtr->checksum = 0;
    icmpPtr->identifier     = OSSwapHostToBigInt16(self.identifier);
    icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
    memcpy(&icmpPtr[1], [payload bytes], [payload length]);
    if (requiresChecksum) {
        // The IP checksum routine returns a 16-bit number that's already in correct byte order
        // (due to wacky 1's complement maths), so we just put it into the packet as a 16-bit unit.
        icmpPtr->checksum = in_cksum(packet.bytes, packet.length);
    }
    return packet;
}
- (void)sendPingWithData:(NSData *)data {
    int                     err;
    NSData *                payload;
    NSData *                packet;
    ssize_t                 bytesSent;
    id<SimplePingDelegate>  strongDelegate;
    // data may be nil
    NSParameterAssert(self.hostAddress != nil);     // gotta wait for -simplePing:didStartWithAddress:
    // Construct the ping packet.
    payload = data;
    if (payload == nil) {
        payload = [[NSString stringWithFormat:@"%28zd bottles of beer on the wall", (ssize_t) 99 - (size_t) (self.nextSequenceNumber % 100) ] dataUsingEncoding:NSASCIIStringEncoding];
        assert(payload != nil);
        // Our dummy payload is sized so that the resulting ICMP packet, including the ICMPHeader, is
        // 64-bytes, which makes it easier to recognise our packets on the wire.
        assert([payload length] == 56);
    }
    switch (self.hostAddressFamily) {
        case AF_INET: {
            packet = [self pingPacketWithType:ICMPv4TypeEchoRequest payload:payload requiresChecksum:YES];
        } break;
        case AF_INET6: {
            packet = [self pingPacketWithType:ICMPv6TypeEchoRequest payload:payload requiresChecksum:NO];
        } break;
        default: {
            assert(NO);
        } break;
    }
    assert(packet != nil);
    // Send the packet.
    if (self.socket == NULL) {
        bytesSent = -1;
        err = EBADF;
    } else {
        bytesSent = sendto(
            CFSocketGetNative(self.socket),
            packet.bytes,
            packet.length,
            0,
            self.hostAddress.bytes,
            (socklen_t) self.hostAddress.length
        );
        err = 0;
        if (bytesSent < 0) {
            err = errno;
        }
    }
    // Handle the results of the send.
    strongDelegate = self.delegate;
    if ( (bytesSent > 0) && (((NSUInteger) bytesSent) == packet.length) ) {
        // Complete success.  Tell the client.
        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didSendPacket:sequenceNumber:)] ) {
            [strongDelegate simplePing:self didSendPacket:packet sequenceNumber:self.nextSequenceNumber];
        }
    } else {
        NSError *   error;
        // Some sort of failure.  Tell the client.
        if (err == 0) {
            err = ENOBUFS;          // This is not a hugely descriptor error, alas.
        }
        static NSInteger number = 0;
        error = [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil];
        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailToSendPacket:sequenceNumber:error:)] ) {
            number ++;
            [strongDelegate simplePing:self didFailToSendPacket:packet sequenceNumber:self.nextSequenceNumber error:error];
        }
    }
    self.nextSequenceNumber += 1;
    if (self.nextSequenceNumber == 0) {
        self.nextSequenceNumberHasWrapped = YES;
    }
}
/*! Calculates the offset of the ICMP header within an IPv4 packet.
 *  \details In the IPv4 case the kernel returns us a buffer that includes the
 *      IPv4 header.  We're not interested in that, so we have to skip over it.
 *      This code does a rough check of the IPv4 header and, if it looks OK,
 *      returns the offset of the ICMP header.
 *  \param packet The IPv4 packet, as returned to us by the kernel.
 *  \returns The offset of the ICMP header, or NSNotFound.
 */
+ (NSUInteger)icmpHeaderOffsetInIPv4Packet:(NSData *)packet {
    // Returns the offset of the ICMPv4Header within an IP packet.
    NSUInteger                  result;
    const struct IPv4Header *   ipPtr;
    size_t                      ipHeaderLength;
    result = NSNotFound;
    if (packet.length >= (sizeof(IPv4Header) + sizeof(ICMPHeader))) {
        ipPtr = (const IPv4Header *) packet.bytes;
        if ( ((ipPtr->versionAndHeaderLength & 0xF0) == 0x40) &&            // IPv4
             ( ipPtr->protocol == IPPROTO_ICMP ) ) {
            ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t);
            if (packet.length >= (ipHeaderLength + sizeof(ICMPHeader))) {
                result = ipHeaderLength;
            }
        }
    }
    return result;
}
/*! Checks whether the specified sequence number is one we sent.
 *  \param sequenceNumber The incoming sequence number.
 *  \returns YES if the sequence number looks like one we sent.
 */
- (BOOL)validateSequenceNumber:(uint16_t)sequenceNumber {
    if (self.nextSequenceNumberHasWrapped) {
        // If the sequence numbers have wrapped that we can't reliably check
        // whether this is a sequence number we sent.  Rather, we check to see
        // whether the sequence number is within the last 120 sequence numbers
        // we sent.  Note that the uint16_t subtraction here does the right
        // thing regardless of the wrapping.
        //
        // Why 120?  Well, if we send one ping per second, 120 is 2 minutes, which
        // is the standard "max time a packet can bounce around the Internet" value.
        return ((uint16_t) (self.nextSequenceNumber - sequenceNumber)) < (uint16_t) 120;
    } else {
        return sequenceNumber < self.nextSequenceNumber;
    }
}
/*! Checks whether an incoming IPv4 packet looks like a ping response.
 *  \details This routine modifies this `packet` data!  It does this for two reasons:
 *
 *      * It needs to zero out the `checksum` field of the ICMPHeader in order to do
 *          its checksum calculation.
 *
 *      * It removes the IPv4 header from the front of the packet.
 *  \param packet The IPv4 packet, as returned to us by the kernel.
 *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
 *  \returns YES if the packet looks like a reasonable IPv4 ping response.
 */
- (BOOL)validatePing4ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
    BOOL                result;
    NSUInteger          icmpHeaderOffset;
    ICMPHeader *        icmpPtr;
    uint16_t            receivedChecksum;
    uint16_t            calculatedChecksum;
    result = NO;
    icmpHeaderOffset = [[self class] icmpHeaderOffsetInIPv4Packet:packet];
    if (icmpHeaderOffset != NSNotFound) {
        icmpPtr = (struct ICMPHeader *) (((uint8_t *) packet.mutableBytes) + icmpHeaderOffset);
        receivedChecksum   = icmpPtr->checksum;
        icmpPtr->checksum  = 0;
        calculatedChecksum = in_cksum(icmpPtr, packet.length - icmpHeaderOffset);
        icmpPtr->checksum  = receivedChecksum;
        if (receivedChecksum == calculatedChecksum) {
            if ( (icmpPtr->type == ICMPv4TypeEchoReply) && (icmpPtr->code == 0) ) {
                if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) {
                    uint16_t    sequenceNumber;
                    sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber);
                    if ([self validateSequenceNumber:sequenceNumber]) {
                        // Remove the IPv4 header off the front of the data we received, leaving us with
                        // just the ICMP header and the ping payload.
                        [packet replaceBytesInRange:NSMakeRange(0, icmpHeaderOffset) withBytes:NULL length:0];
                        *sequenceNumberPtr = sequenceNumber;
                        result = YES;
                    }
                }
            }
        }
    }
    return result;
}
/*! Checks whether an incoming IPv6 packet looks like a ping response.
 *  \param packet The IPv6 packet, as returned to us by the kernel; note that this routine
 *      could modify this data but does not need to in the IPv6 case.
 *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
 *  \returns YES if the packet looks like a reasonable IPv4 ping response.
 */
- (BOOL)validatePing6ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
    BOOL                    result;
    const ICMPHeader *      icmpPtr;
    result = NO;
    if (packet.length >= sizeof(*icmpPtr)) {
        icmpPtr = packet.bytes;
        // In the IPv6 case we don't check the checksum because that's hard (we need to
        // cook up an IPv6 pseudo header and we don't have the ingredients) and unnecessary
        // (the kernel has already done this check).
        if ( (icmpPtr->type == ICMPv6TypeEchoReply) && (icmpPtr->code == 0) ) {
            if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) {
                uint16_t    sequenceNumber;
                sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber);
                if ([self validateSequenceNumber:sequenceNumber]) {
                    *sequenceNumberPtr = sequenceNumber;
                    result = YES;
                }
            }
        }
    }
    return result;
}
/*! Checks whether an incoming packet looks like a ping response.
 *  \param packet The packet, as returned to us by the kernel; note that may end up modifying
 *      this data.
 *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
 *  \returns YES if the packet looks like a reasonable IPv4 ping response.
 */
- (BOOL)validatePingResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
    BOOL        result;
    switch (self.hostAddressFamily) {
        case AF_INET: {
            result = [self validatePing4ResponsePacket:packet sequenceNumber:sequenceNumberPtr];
        } break;
        case AF_INET6: {
            result = [self validatePing6ResponsePacket:packet sequenceNumber:sequenceNumberPtr];
        } break;
        default: {
            assert(NO);
            result = NO;
        } break;
    }
    return result;
}
/*! Reads data from the ICMP socket.
 *  \details Called by the socket handling code (SocketReadCallback) to process an ICMP
 *      message waiting on the socket.
 */
- (void)readData {
    int                     err;
    struct sockaddr_storage addr;
    socklen_t               addrLen;
    ssize_t                 bytesRead;
    void *                  buffer;
    enum { kBufferSize = 65535 };
    // 65535 is the maximum IP packet size, which seems like a reasonable bound
    // here (plus it's what <x-man-page://8/ping> uses).
    buffer = malloc(kBufferSize);
    assert(buffer != NULL);
    // Actually read the data.  We use recvfrom(), and thus get back the source address,
    // but we don't actually do anything with it.  It would be trivial to pass it to
    // the delegate but we don't need it in this example.
    addrLen = sizeof(addr);
    bytesRead = recvfrom(CFSocketGetNative(self.socket), buffer, kBufferSize, 0, (struct sockaddr *) &addr, &addrLen);
    err = 0;
    if (bytesRead < 0) {
        err = errno;
    }
    // Process the data we read.
    if (bytesRead > 0) {
        NSMutableData *         packet;
        id<SimplePingDelegate>  strongDelegate;
        uint16_t                sequenceNumber;
        packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger) bytesRead];
        assert(packet != nil);
        // We got some data, pass it up to our client.
        strongDelegate = self.delegate;
        if ( [self validatePingResponsePacket:packet sequenceNumber:&sequenceNumber] ) {
            if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceivePingResponsePacket:sequenceNumber:)] ) {
                [strongDelegate simplePing:self didReceivePingResponsePacket:packet sequenceNumber:sequenceNumber];
            }
        } else {
            if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceiveUnexpectedPacket:)] ) {
                [strongDelegate simplePing:self didReceiveUnexpectedPacket:packet];
            }
        }
    } else {
        // We failed to read the data, so shut everything down.
        if (err == 0) {
            err = EPIPE;
        }
        [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
    }
    free(buffer);
    // Note that we don't loop back trying to read more data.  Rather, we just
    // let CFSocket call us again.
}
/*! The callback for our CFSocket object.
 *  \details This simply routes the call to our `-readData` method.
 *  \param s See the documentation for CFSocketCallBack.
 *  \param type See the documentation for CFSocketCallBack.
 *  \param address See the documentation for CFSocketCallBack.
 *  \param data See the documentation for CFSocketCallBack.
 *  \param info See the documentation for CFSocketCallBack; this is actually a pointer to the
 *      'owning' object.
 */
static void SocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
    // This C routine is called by CFSocket when there's data waiting on our
    // ICMP socket.  It just redirects the call to Objective-C code.
    SimplePing *    obj;
    obj = (__bridge SimplePing *) info;
    assert([obj isKindOfClass:[SimplePing class]]);
    #pragma unused(s)
    assert(s == obj.socket);
    #pragma unused(type)
    assert(type == kCFSocketReadCallBack);
    #pragma unused(address)
    assert(address == nil);
    #pragma unused(data)
    assert(data == nil);
    [obj readData];
}
/*! Starts the send and receive infrastructure.
 *  \details This is called once we've successfully resolved `hostName` in to
 *      `hostAddress`.  It's responsible for setting up the socket for sending and
 *      receiving pings.
 */
- (void)startWithHostAddress {
    int                     err;
    int                     fd;
    assert(self.hostAddress != nil);
    // Open the socket.
    fd = -1;
    err = 0;
    switch (self.hostAddressFamily) {
        case AF_INET: {
            fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
            if (fd < 0) {
                err = errno;
            }
        } break;
        case AF_INET6: {
            fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
            if (fd < 0) {
                err = errno;
            }
        } break;
        default: {
            err = EPROTONOSUPPORT;
        } break;
    }
    if (err != 0) {
        [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
    } else {
        CFSocketContext         context = {0, (__bridge void *)(self), NULL, NULL, NULL};
        CFRunLoopSourceRef      rls;
        id<SimplePingDelegate>  strongDelegate;
        // Wrap it in a CFSocket and schedule it on the runloop.
        self.socket = (CFSocketRef) CFAutorelease( CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack, SocketReadCallback, &context) );
        assert(self.socket != NULL);
        // The socket will now take care of cleaning up our file descriptor.
        assert( CFSocketGetSocketFlags(self.socket) & kCFSocketCloseOnInvalidate );
        fd = -1;
        rls = CFSocketCreateRunLoopSource(NULL, self.socket, 0);
        assert(rls != NULL);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
        CFRelease(rls);
        strongDelegate = self.delegate;
        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didStartWithAddress:)] ) {
            [strongDelegate simplePing:self didStartWithAddress:self.hostAddress];
        }
    }
    assert(fd == -1);
}
/*! Processes the results of our name-to-address resolution.
 *  \details Called by our CFHost resolution callback (HostResolveCallback) when host
 *      resolution is complete.  We just latch the first appropriate address and kick
 *      off the send and receive infrastructure.
 */
- (void)hostResolutionDone {
    Boolean     resolved;
    NSArray *   addresses;
    // Find the first appropriate address.
    addresses = (__bridge NSArray *) CFHostGetAddressing(self.host, &resolved);
    if ( resolved && (addresses != nil) ) {
        resolved = false;
        for (NSData * address in addresses) {
            const struct sockaddr * addrPtr;
            addrPtr = (const struct sockaddr *) address.bytes;
            if ( address.length >= sizeof(struct sockaddr) ) {
                switch (addrPtr->sa_family) {
                    case AF_INET: {
                        if (self.addressStyle != SimplePingAddressStyleICMPv6) {
                            self.hostAddress = address;
                            resolved = true;
                        }
                    } break;
                    case AF_INET6: {
                        if (self.addressStyle != SimplePingAddressStyleICMPv4) {
                            self.hostAddress = address;
                            resolved = true;
                        }
                    } break;
                }
            }
            if (resolved) {
                break;
            }
        }
    }
    // We're done resolving, so shut that down.
    [self stopHostResolution];
    // If all is OK, start the send and receive infrastructure, otherwise stop.
    if (resolved) {
        [self startWithHostAddress];
    } else {
        [self didFailWithError:[NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorHostNotFound userInfo:nil]];
    }
}
/*! The callback for our CFHost object.
 *  \details This simply routes the call to our `-hostResolutionDone` or
 *      `-didFailWithHostStreamError:` methods.
 *  \param theHost See the documentation for CFHostClientCallBack.
 *  \param typeInfo See the documentation for CFHostClientCallBack.
 *  \param error See the documentation for CFHostClientCallBack.
 *  \param info See the documentation for CFHostClientCallBack; this is actually a pointer to
 *      the 'owning' object.
 */
static void HostResolveCallback(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info) {
    // This C routine is called by CFHost when the host resolution is complete.
    // It just redirects the call to the appropriate Objective-C method.
    SimplePing *    obj;
    obj = (__bridge SimplePing *) info;
    assert([obj isKindOfClass:[SimplePing class]]);
    #pragma unused(theHost)
    assert(theHost == obj.host);
    #pragma unused(typeInfo)
    assert(typeInfo == kCFHostAddresses);
    if ( (error != NULL) && (error->domain != 0) ) {
        [obj didFailWithHostStreamError:*error];
    } else {
        [obj hostResolutionDone];
    }
}
- (void)start {
    Boolean             success;
    CFHostClientContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
    CFStreamError       streamError;
    assert(self.host == NULL);
    assert(self.hostAddress == nil);
    self.host = (CFHostRef) CFAutorelease( CFHostCreateWithName(NULL, (__bridge CFStringRef) self.hostName) );
    assert(self.host != NULL);
    CFHostSetClient(self.host, HostResolveCallback, &context);
    CFHostScheduleWithRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    success = CFHostStartInfoResolution(self.host, kCFHostAddresses, &streamError);
    if ( ! success ) {
        [self didFailWithHostStreamError:streamError];
    }
}
/*! Stops the name-to-address resolution infrastructure.
 */
- (void)stopHostResolution {
    // Shut down the CFHost.
    if (self.host != NULL) {
        CFHostSetClient(self.host, NULL, NULL);
        CFHostUnscheduleFromRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
        self.host = NULL;
    }
}
/*! Stops the send and receive infrastructure.
 */
- (void)stopSocket {
    if (self.socket != NULL) {
        CFSocketInvalidate(self.socket);
        self.socket = NULL;
    }
}
- (void)stop {
    [self stopHostResolution];
    [self stopSocket];
    // Junk the host address on stop.  If the client calls -start again, we'll
    // re-resolve the host name.
    self.hostAddress = NULL;
}
@end
MIduo/Êý¾Ý/lib/SGNetObserver/SimplePinger.h
New file
@@ -0,0 +1,50 @@
//
//  SimpleHeartbeat.h
//  SGNetObserverDemo
//
//  Created by apple on 16/9/20.
//  Copyright Â© 2016å¹´ iOSSinger. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SimplePing.h"
@interface SimplePinger : NSObject
/**
 *  æ˜¯å¦ping的通
 */
@property (nonatomic,assign) BOOL reachable;
/**
 *  æœ‰å¾ˆå°æ¦‚率ping失败,设定多少次ping失败认为是断网,默认2次, å¿…é¡» >= 2
 */
@property (nonatomic,assign) NSUInteger failureTimes;
/**
 *  ping çš„频率,默认1s
 */
@property (nonatomic,assign) NSTimeInterval interval;
/**
 *  æ˜¯å¦æ”¯æŒIPv4,默认全部支持
 */
@property (nonatomic,assign) BOOL supportIPv4;
/**
 *  æ˜¯å¦æ”¯æŒIPv6
 */
@property (nonatomic,assign) BOOL supportIPv6;
/**
 *  å›žè°ƒ
 */
@property (nonatomic,copy) void(^networkStatusDidChanged)();
+ (instancetype)simplePingerWithHostName:(NSString *)hostName;
- (void)startNotifier;
- (void)stopNotifier;
@end
MIduo/Êý¾Ý/lib/SGNetObserver/SimplePinger.m
New file
@@ -0,0 +1,188 @@
//
//  SimpleHeartbeat.m
//  SGNetObserverDemo
//
//  Created by apple on 16/9/20.
//  Copyright Â© 2016å¹´ iOSSinger. All rights reserved.
//
#import "SimplePinger.h"
#import "SimplePing.h"
#include <netdb.h>
@interface SimplePinger()<SimplePingDelegate>
@property (nonatomic,strong) SimplePing *pinger;
@property (nonatomic,copy)   NSString *hostName;
@property (nonatomic,strong) NSTimer *sendTimer;
/**
 *  å‘送失败记录,失败次数为failuretimes时,认为断网.
 */
@property (nonatomic,strong) NSMutableArray *array;
@end
@implementation SimplePinger
#pragma mark - åˆå§‹åŒ–
+ (instancetype)simplePingerWithHostName:(NSString *)hostName{
    SimplePinger *pinger = [[SimplePinger alloc] init];
    pinger.hostName = hostName;
    return pinger;
}
- (instancetype)init{
    if(self = [super init]){
        self.interval = 1.0;
        self.failureTimes = 2;
        self.reachable = YES;
    }
    return self;
}
- (void)dealloc{
    [self stopPing];
    [self.array removeAllObjects];
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(sendPing) object:nil];
}
#pragma mark - function
- (void)startNotifier{
    [self startForceIPv4:self.supportIPv4 forceIPv6:self.supportIPv6];
}
- (void)stopNotifier{
    [self stopPing];
}
- (void)startForceIPv4:(BOOL)forceIPv4 forceIPv6:(BOOL)forceIPv6{
    self.pinger = [[SimplePing alloc] initWithHostName:self.hostName];
    if (forceIPv4 && !forceIPv6) {
        self.pinger.addressStyle = SimplePingAddressStyleICMPv4;
    }else if (forceIPv6 && !forceIPv4){
        self.pinger.addressStyle = SimplePingAddressStyleICMPv6;
    }else{
        self.pinger.addressStyle = SimplePingAddressStyleAny;
    }
    self.pinger.delegate = self;
    [self.pinger start];
}
- (void)sendPing{
    static NSInteger number = 0;
    if (number < 3) {
        number ++;
        [self.pinger sendPingWithData:nil];
    }else{
        [_sendTimer invalidate];
        _sendTimer = nil;
    }
}
- (void)stopPing{
    [self.pinger stop];
     self.pinger.delegate = nil;
     self.pinger = nil;
    [self.sendTimer invalidate];
     self.sendTimer = nil;
}
#pragma mark - delegaet
- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address{
    NSLog(@"didStartPingWithAddress: %@",[self addressWithData:address]);
    [self sendPing];
    if (!_sendTimer) {
        _sendTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(sendPing) userInfo:nil repeats:YES];
    }
}
//发送成功,sequenceNumber范围:0~65535,超范围后从 0 å¼€å§‹
- (void)simplsentePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber{
     NSLog(@"#%u sent", sequenceNumber);
    if(sequenceNumber == 0){//重置
        [self.array removeAllObjects];
    }
    //根据failuretimes判断是否有网
    if (self.array.count >= self.failureTimes) {
        self.reachable = NO;
        [self.array removeAllObjects];
    }
    //将本次记录加入
    [self.array addObject:@(sequenceNumber)];
}
//发送失败
- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error{
    NSLog(@"#%u fail sent",sequenceNumber);
    //发送失败,直接认为断网
     self.reachable = NO;
    [self.array removeAllObjects];
}
//接收成功
- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber{
    //有网
     self.reachable = YES;
    [self.array removeAllObjects];
}
//未知失败,重启ping
- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error{
     self.reachable = NO;
    [self stopPing];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self startNotifier];
    });
}
//根据data,计算host
- (NSString *)addressWithData:(NSData *)address{
    char *hostStr = malloc(NI_MAXHOST);
    memset(hostStr, 0, NI_MAXHOST);
    BOOL success = getnameinfo((const struct sockaddr *)address.bytes, (socklen_t)address.length, hostStr, (socklen_t)NI_MAXHOST, nil, 0, NI_NUMERICHOST) == 0;
    NSString *result;
    if (success) {
        result = [NSString stringWithUTF8String:hostStr];
    }else{
        result = @"?";
    }
    free(hostStr);
    return  result;
}
#pragma mark - setter
- (void)setReachable:(BOOL)reachable{
    if (_reachable != reachable) {
        _reachable = reachable;
        if (self.networkStatusDidChanged) {
            self.networkStatusDidChanged();
        }
    }
}
- (void)setFailureTimes:(NSUInteger)failureTimes{
    if (failureTimes < 2) {
        failureTimes = 2;
    }
    _failureTimes = failureTimes;
}
- (NSMutableArray *)array{
    if (_array == nil) {
        _array = [NSMutableArray array];
    }
    return _array;
}
@end
MIduo/½çÃæ/ÓÅ»Ýȯ/ÍÆ¼ö/RecommendCouponViewController.m
@@ -169,7 +169,7 @@
    [[YTHNetInterface startInterface] getCouponListWithPage:[NSString stringWithFormat:@"%ld",(long)self.page] Withblock:^(BOOL isSuccessful, id result, NSString *error) {
        if (isSuccessful) {
            
            //self.adviceTableview.hidden = NO;
            self.adviceTableview.hidden = NO;
            
            NSDictionary *tempDic=(NSDictionary *)result;
            
@@ -207,17 +207,26 @@
                if (self.GoodsData.count != 0) {
                    
                    //self.adviceTableview.hidden = NO;
                      self.adviceTableview.hidden = YES;
                    
                    [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
                } else {
                      self.adviceTableview.hidden = NO;
                }
                
            } else {
                
                if (self.GoodsData.count != 0) {
                    
                    // self.adviceTableview.hidden = NO;
                     self.adviceTableview.hidden = YES;
                    
                    [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
                } else {
                      self.adviceTableview.hidden = NO;
                }
            }
        }
@@ -455,7 +464,7 @@
        // Fallback on earlier versions
    }
    
    // _adviceTableview.hidden = YES;
    _adviceTableview.hidden = YES;
    _adviceTableview.separatorStyle = UITableViewCellSeparatorStyleNone;
    return _adviceTableview;
}
MIduo/½çÃæ/ÎÒµÄ/LoginViewController.m
@@ -343,11 +343,13 @@
        return ;
    }
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    [YTHsharedManger startManger].isBound = NO;
@@ -425,11 +427,13 @@
 */
- (IBAction)clickAgreement:(id)sender {
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
         [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
         [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    XYRWebViewController *aboutWebVC=[[XYRWebViewController alloc] init];
MIduo/½çÃæ/ÎÒµÄ/SJUnbindPhoneViewController.m
@@ -75,11 +75,13 @@
        return;
    }
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    NSMutableDictionary *dic = @{}.mutableCopy;
MIduo/½çÃæ/ÎÒµÄ/balance/ÌåÏÖ/AddIncarnateViewController.m
@@ -12,6 +12,7 @@
@interface AddIncarnateViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameText;
@property (weak, nonatomic) IBOutlet UITextField *zhifubaoText;
@property (weak, nonatomic) IBOutlet UILabel *labelTips;
@end
MIduo/½çÃæ/ÎÒµÄ/balance/ÌåÏÖ/AddIncarnateViewController.xib
@@ -12,6 +12,7 @@
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AddIncarnateViewController">
            <connections>
                <outlet property="labelTips" destination="Mjp-Hv-7Kn" id="8Ag-SG-y6C"/>
                <outlet property="nameText" destination="2AH-UX-SdD" id="85m-8D-xRU"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="zhifubaoText" destination="sXz-cR-dZt" id="MCT-y7-0eQ"/>
@@ -22,8 +23,27 @@
            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2Pu-tB-RuN">
                    <rect key="frame" x="0.0" y="0.0" width="375" height="40"/>
                    <subviews>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="为确保你的资金安全,请准确填写账号对应信息!" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mjp-Hv-7Kn">
                            <rect key="frame" x="15" y="0.0" width="360" height="40"/>
                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
                            <color key="textColor" red="0.88235294117647056" green="0.47450980392156861" blue="0.47450980392156861" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
                        </label>
                    </subviews>
                    <color key="backgroundColor" red="1" green="0.99215686274509807" blue="0.88235294117647056" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="40" id="Jba-th-BfX"/>
                        <constraint firstItem="Mjp-Hv-7Kn" firstAttribute="top" secondItem="2Pu-tB-RuN" secondAttribute="top" id="cdJ-j6-ufJ"/>
                        <constraint firstAttribute="trailing" secondItem="Mjp-Hv-7Kn" secondAttribute="trailing" id="csy-sx-Wio"/>
                        <constraint firstAttribute="bottom" secondItem="Mjp-Hv-7Kn" secondAttribute="bottom" id="j5F-ZI-JCk"/>
                        <constraint firstItem="Mjp-Hv-7Kn" firstAttribute="leading" secondItem="2Pu-tB-RuN" secondAttribute="leading" constant="15" id="mIE-Vb-Pbe"/>
                    </constraints>
                </view>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W5U-xK-P7j">
                    <rect key="frame" x="0.0" y="10" width="375" height="160"/>
                    <rect key="frame" x="0.0" y="50" width="375" height="160"/>
                    <subviews>
                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="支付宝" translatesAutoresizingMaskIntoConstraints="NO" id="ARx-dm-zbb">
                            <rect key="frame" x="20" y="20" width="35" height="35"/>
@@ -112,7 +132,7 @@
                    </constraints>
                </view>
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JuN-HO-zP5">
                    <rect key="frame" x="94" y="200" width="187.5" height="34"/>
                    <rect key="frame" x="94" y="240" width="187.5" height="34"/>
                    <color key="backgroundColor" red="0.93333333333333335" green="0.26666666666666666" blue="0.27843137254901962" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="34" id="oyG-23-J3x"/>
@@ -133,9 +153,12 @@
            <constraints>
                <constraint firstItem="W5U-xK-P7j" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="7Ra-gr-YCo"/>
                <constraint firstItem="JuN-HO-zP5" firstAttribute="top" secondItem="W5U-xK-P7j" secondAttribute="bottom" constant="30" id="7lv-7o-qnT"/>
                <constraint firstItem="W5U-xK-P7j" firstAttribute="top" secondItem="2Pu-tB-RuN" secondAttribute="bottom" constant="10" id="ByE-2u-7dv"/>
                <constraint firstAttribute="trailing" secondItem="W5U-xK-P7j" secondAttribute="trailing" id="Ua1-GY-v7b"/>
                <constraint firstItem="2Pu-tB-RuN" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="Uu2-Tc-kZs"/>
                <constraint firstItem="JuN-HO-zP5" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Wt6-GG-4LO"/>
                <constraint firstItem="W5U-xK-P7j" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="10" id="xsV-dF-e1N"/>
                <constraint firstItem="2Pu-tB-RuN" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="ehl-Dv-eZ9"/>
                <constraint firstAttribute="trailing" secondItem="2Pu-tB-RuN" secondAttribute="trailing" id="fNv-dq-C80"/>
                <constraint firstItem="JuN-HO-zP5" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" multiplier="1:2" id="zNI-dX-jTv"/>
            </constraints>
            <point key="canvasLocation" x="33.5" y="53.5"/>
MIduo/½çÃæ/ÎÒµÄ/balance/Ã÷ϸ/BalaDetailViewController.m
@@ -84,7 +84,8 @@
            }
        }else{
            [self autoDisappearAlertTime:0.5 msg:object[@"msg"]];
            [CustomProgressHUD showNormal:object[@"msg"]];
            
        }
       
MIduo/½çÃæ/ÎÒµÄ/collection/MinCollectViewController.m
@@ -246,8 +246,8 @@
            }
            [self.collectview.mj_header endRefreshing];
        }else{
            [self autoDisappearAlertTime:0.5 msg:object[@"msg"]];
            [CustomProgressHUD showNormal:object[@"msg"]];
        }
    } fail:^(id object) {
MIduo/½çÃæ/ÎÒµÄ/message/MineMessageViewController.m
@@ -99,7 +99,7 @@
            }
            NSLog(@"%@",self.datasource);
        }else{
            [self autoDisappearAlertTime:0.5 msg:object[@"msg"]];
            [CustomProgressHUD showNormal:object[@"msg"]];
        }
        
    } fail:^(id object) {
MIduo/½çÃæ/ÎÒµÄ/messageLogin/MessageLoginViewController.m
@@ -175,11 +175,13 @@
        return;
    }
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    if (self.passwordText.text.length != 6) {
@@ -412,11 +414,13 @@
        return;
    }
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    [self.passwordText  becomeFirstResponder ];
MIduo/½çÃæ/ÎÒµÄ/userInfoViewController.m
@@ -260,11 +260,13 @@
    if (indexPath.section==1) {
        //用户点击了,可能是绑定,可能是解绑,需要判断
        if ([YTHsharedManger startManger].networkStatus == 0) {
            [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
            [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
            return;
        }
        if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
            [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
            [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
            return ;
        }
        if (indexPath.row==0) {//淘宝
@@ -315,11 +317,14 @@
            }
        }else if(indexPath.row == 1){//微信
            if ([YTHsharedManger startManger].networkStatus == 0) {
                [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
                  [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
                return;
            }
            if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
                [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
                  [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
                return ;
            }
            NSString *wxOpenId = [_userInfo objectForKey:@"wxOpenId"];
MIduo/½çÃæ/ÍøÒ³ÊÓͼ/OrderViewController.m
@@ -361,7 +361,8 @@
                [self.orderTableView.mj_footer endRefreshingWithNoMoreData];
            }
        }else{
            [self autoDisappearAlertTime:0.5 msg:object[@"msg"]];
            [CustomProgressHUD showNormal:object[@"msg"]];
        }
    } fail:^(id object) {
MIduo/½çÃæ/ÍøÒ³ÊÓͼ/ÉÌÆ·ÏêÇé/GoodDeTrViewController.m
@@ -183,11 +183,13 @@
 */
- (void)fecthAndPostCollection {
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
         [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    self.buttomView.collectButton.enabled = NO;
@@ -543,10 +545,12 @@
                   if (self.recommendArray.count != 0) {
                       
                       if (error.code == -1009) {
                           [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
                           [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
                           
                       }else{
                           [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
                           [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
                       }
                   }
               }];
@@ -556,11 +560,13 @@
- (void)useQuanClicked:(GoodsHeaderTableViewCell *)cell {
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    if (![[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]) {
@@ -615,11 +621,13 @@
#pragma mark - ButtomCarViewDelegate
- (void)shareClicked:(ButtomCarView *)view {
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    if (![[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]) {
@@ -664,11 +672,13 @@
 */
- (void)buyClicked:(ButtomCarView *)view {
    if ([YTHsharedManger startManger].networkStatus == 0) {
        [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
        [CustomProgressHUD showNormal:@"未连接,请检测网络设置"];
        return;
    }
    if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
        [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
        [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
        return ;
    }
    if (![[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]) {
MIduo/½çÃæ/ÑûÇë/ÉÌÆ··ÖÏí/ShonpingShareViewController.m
@@ -275,12 +275,16 @@
    }
    if ( [urlString containsString:@"yeshitv://fanli_invite"]) {
        if ([YTHsharedManger startManger].networkStatus == 0) {
            [self autoDisappearAlertTime:0.5 msg:@"网络未连接,请检测网络设置"];
            [CustomProgressHUD showNormal:@"网络未连接,请检测网络设置"];
            return NO;
        }
        
        if ([YTHsharedManger startManger].isCheckNetCanUse == -2) {
            [self autoDisappearAlertTime:0.5 msg:@"网络连接异常,请检测网络设置"];
            [CustomProgressHUD showNormal:@"网络连接异常,请检测网络设置"];
            return NO;
        }
        InvitationFriendsViewController *invitaVC = [[InvitationFriendsViewController alloc]init];
MIduo/½çÃæ/Ê×Ò³/ListViewController.m
@@ -39,6 +39,9 @@
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"networkError" object:nil];
    self.view.backgroundColor= YTHColor(239, 239, 239);
    _huojianW.constant=33*KScreenW/320;
    self.title = @"首页";