美文网首页
iOS学习之AFNetworking(一)-AFNetworki

iOS学习之AFNetworking(一)-AFNetworki

作者: c1442725faa6 | 来源:发表于2016-05-10 17:52 被阅读510次

    AFNetworkingReachabilityManager.h

    #import <Foundation/Foundation.h>
    
    #if !TARGET_OS_WATCH
    #import <SystemConfiguration/SystemConfiguration.h>
    
    typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
        AFNetworkReachabilityStatusUnknown          = -1,
        AFNetworkReachabilityStatusNotReachable     = 0,
        AFNetworkReachabilityStatusReachableViaWWAN = 1,
        AFNetworkReachabilityStatusReachableViaWiFi = 2,
    };
    
    NS_ASSUME_NONNULL_BEGIN
    
    
    @interface AFNetworkReachabilityManager : NSObject
    
    /**
     当前网络连接状态.
     */
    @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
    
    /**
     当前网络是否可用
     */
    @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
    
    /**
    当前网络是否可以通过WWAN进行连接.
     */
    @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
    
    /**
     当前网络是否可以通过 WiFi进行连接.
     */
    @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
    
    /**
     返回一个单例的manager对象.
     */
    + (instancetype)sharedManager;
    
    /**
     创建并返回一个默认socket地址的manager对象
     */
    + (instancetype)manager;
    
    /**
     为指定的域名返回一个manager对象
     */
    + (instancetype)managerForDomain:(NSString *)domain;
    
    /**
     为制定的Socket地址返回一个manager对象
     */
    + (instancetype)managerForAddress:(const void *)address;
    
    /**
     为特定的reachability对象返回一个manager对象
     */
    - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
    
    /**
    开始监听网络连接状态
     */
    - (void)startMonitoring;
    
    /**
    停止监听网络连接状态
     */
    - (void)stopMonitoring;
    
    /**
    返回一个本地化的网络状态字符串
     */
    - (NSString *)localizedNetworkReachabilityStatusString;
    
    /**
     当网络状态发生变化的时候调用此方法,设置回调函数进行调用.
     */
    - (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
    
    @end
    
    FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
    FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
    FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
    
    NS_ASSUME_NONNULL_END
    #endif
    

    AFNetworkingReachabilityManager.m

    #import "AFNetworkReachabilityManager.h"
    #if !TARGET_OS_WATCH
    
    #import <netinet/in.h>
    #import <netinet6/in6.h>
    #import <arpa/inet.h>
    #import <ifaddrs.h>
    #import <netdb.h>
    
    NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
    NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
    
    typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
    
    NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusNotReachable:
                return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
            case AFNetworkReachabilityStatusReachableViaWWAN:
                return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
            case AFNetworkReachabilityStatusReachableViaWiFi:
                return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
            case AFNetworkReachabilityStatusUnknown:
            default:
                return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
        }
    }
    
    static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
        BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
        BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
        BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
        BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
        BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));
    
        AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
        if (isNetworkReachable == NO) {
            status = AFNetworkReachabilityStatusNotReachable;
        }
    #if TARGET_OS_IPHONE
        else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
            status = AFNetworkReachabilityStatusReachableViaWWAN;
        }
    #endif
        else {
            status = AFNetworkReachabilityStatusReachableViaWiFi;
        }
    
        return status;
    }
    
    /**
     * 为主线程创建一个状态改变的通知的队列
     * 用来保证接收到的通知在按顺序排列
     * 如果通知直接发出,而不再队列中可能会导致多线程错误.
     */
    static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
        AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
        dispatch_async(dispatch_get_main_queue(), ^{
            if (block) {
                block(status);
            }
            NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
            NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
            [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
        });
    }
    
    static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
        AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
    }
    
    
    static const void * AFNetworkReachabilityRetainCallback(const void *info) {
        return Block_copy(info);
    }
    
    static void AFNetworkReachabilityReleaseCallback(const void *info) {
        if (info) {
            Block_release(info);
        }
    }
    
    @interface AFNetworkReachabilityManager ()
    @property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
    @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
    @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
    @end
    
    @implementation AFNetworkReachabilityManager
    
    + (instancetype)sharedManager {
        static AFNetworkReachabilityManager *_sharedManager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _sharedManager = [self manager];
        });
    
        return _sharedManager;
    }
    
    + (instancetype)managerForDomain:(NSString *)domain {
        SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
    
        AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
        
        CFRelease(reachability);
    
        return manager;
    }
    
    + (instancetype)managerForAddress:(const void *)address {
        SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
        AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    
        CFRelease(reachability);
        
        return manager;
    }
    
    + (instancetype)manager
    {
    #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
        struct sockaddr_in6 address;
        bzero(&address, sizeof(address));
        address.sin6_len = sizeof(address);
        address.sin6_family = AF_INET6;
    #else
        struct sockaddr_in address;
        bzero(&address, sizeof(address));
        address.sin_len = sizeof(address);
        address.sin_family = AF_INET;
    #endif
        return [self managerForAddress:&address];
    }
    
    - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
        self = [super init];
        if (!self) {
            return nil;
        }
    
        _networkReachability = CFRetain(reachability);
        self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
    
        return self;
    }
    
    - (instancetype)init NS_UNAVAILABLE
    {
        return nil;
    }
    
    - (void)dealloc {
        [self stopMonitoring];
        
        if (_networkReachability != NULL) {
            CFRelease(_networkReachability);
        }
    }
    
    #pragma mark -
    
    - (BOOL)isReachable {
        return [self isReachableViaWWAN] || [self isReachableViaWiFi];
    }
    
    - (BOOL)isReachableViaWWAN {
        return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
    }
    
    - (BOOL)isReachableViaWiFi {
        return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
    }
    
    #pragma mark -
    
    - (void)startMonitoring {
        [self stopMonitoring];
    
        if (!self.networkReachability) {
            return;
        }
    
        __weak __typeof(self)weakSelf = self;
        AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
    
            strongSelf.networkReachabilityStatus = status;
            if (strongSelf.networkReachabilityStatusBlock) {
                strongSelf.networkReachabilityStatusBlock(status);
            }
    
        };
    
        SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
        SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
        SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
            SCNetworkReachabilityFlags flags;
            if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
                AFPostReachabilityStatusChange(flags, callback);
            }
        });
    }
    
    - (void)stopMonitoring {
        if (!self.networkReachability) {
            return;
        }
    
        SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    }
    
    #pragma mark -
    
    - (NSString *)localizedNetworkReachabilityStatusString {
        return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
    }
    
    #pragma mark -
    
    - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
        self.networkReachabilityStatusBlock = block;
    }
    
    #pragma mark - NSKeyValueObserving
    
    + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
        if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
            return [NSSet setWithObject:@"networkReachabilityStatus"];
        }
    
        return [super keyPathsForValuesAffectingValueForKey:key];
    }
    
    @end
    #endif

    相关文章

      网友评论

          本文标题:iOS学习之AFNetworking(一)-AFNetworki

          本文链接:https://www.haomeiwen.com/subject/gtyyrttx.html