养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要。记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点。它就像时间一样,会自己消散。

前言

终于写完了 AFNetworking 的源码解读。这一过程耗时数天。当我回过头又重头到尾的读了一篇,又有所收获。不禁让我想起了当初上学时的种种情景。我们应该对知识进行反复的记忆和理解。下边是我总结的 AFNetworking 中能够学到的知识点。

1.枚举(enum)

使用原则:当满足一个有限的并具有统一主题的集合的时候,我们就考虑使用枚举。这在很多框架中都验证了这个原则。最重要的是能够增加程序的可读性

示例代码:

  1. /**
  2. * 网络类型 (需要封装为一个自己的枚举)
  3. */
  4. typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
  5. /**
  6. * 未知
  7. */
  8. AFNetworkReachabilityStatusUnknown = -1,
  9. /**
  10. * 无网络
  11. */
  12. AFNetworkReachabilityStatusNotReachable = 0,
  13. /**
  14. * WWAN 手机自带网络
  15. */
  16. AFNetworkReachabilityStatusReachableViaWWAN = 1,
  17. /**
  18. * WiFi
  19. */
  20. AFNetworkReachabilityStatusReachableViaWiFi = 2,
  21. };

2.注释

我们必须知道一个事实,注释的代码是不会编译到目标文件的,因此放心大胆的注释吧。在平日里的开发中,应该经常问问自己是否把每段代码都当成写API那样对待?

曾经看过两种不同的说辞,一种是说把代码注释尽量少些,要求代码简介可读性强。另一种是说注释要详细,着重考虑他人读代码的感受。个人感觉还是写详细一点比较好,因为可能过一段时间之后,自己再去看自己当时写的代码可能就不记得了。很有可能在写这些繁琐的注释的过程中,能够想到些什么,比如如何合并掉一些没必要的方法等等。

示例代码:

  1. /*!
  2. @header SCNetworkReachability
  3. @discussion The SCNetworkReachability API allows an application to
  4. determine the status of a system's current network
  5. configuration and the reachability of a target host.
  6. In addition, reachability can be monitored with notifications
  7. that are sent when the status has changed.
  8. "Reachability" reflects whether a data packet, sent by
  9. an application into the network stack, can leave the local
  10. computer.
  11. Note that reachability does <i>not</i> guarantee that the data
  12. packet will actually be received by the host.
  13. */
  14. /*!
  15. @typedef SCNetworkReachabilityRef
  16. @discussion This is the handle to a network address or name.
  17. */
  18. typedef const struct CF_BRIDGED_TYPE(id) __SCNetworkReachability * SCNetworkReachabilityRef;

3.BOOL属性的property书写规则

通常我们在定义一个BOOL属性的时候,要自定义getter方法,这样做的目的是为了增加程序的可读性。Apple中的代码也是这么写的。

示例代码:

  1. /**
  2. Whether or not the network is currently reachable.
  3. */
  4. @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
  5. // setter
  6. self.reachable = YES;
  7. // getter
  8. if (self.isReachable) {}

4.按功能区分代码

假如我们写的一个控制器中大概有500行代码,我们应该保证能够快速的找到我们需要查找的内容,这就需要把代码按照功能来分隔。

通常在.h中 我们可以使用一个自定义的特殊的注释来分隔,在.m中使用#pragma mark -来分隔。

示例代码:

  1. ///---------------------
  2. /// @name Initialization
  3. ///---------------------
  4. ///------------------------------
  5. /// @name Evaluating Server Trust
  6. ///------------------------------
  7. #pragma mark - UI
  8. ...设置UI相关
  9. #pragma mark - Data
  10. ...处理数据
  11. #pragma mark - Action
  12. ...点击事件

5.通知

我们都知道通知可以用来传递事件和数据,但要想用好它,也不太容易。在 AFNetworking 事件和数据的传递使用的是通知和Block,按照AFNetworking对通知的使用习惯。我总结了几点:

  • 原则:如果我们需要传递事件或数据,可采用代理和Block,同时额外增加一个通知。因为通知具有跨多个界面的优点。
  • 释放问题:在接收通知的页面,一定要记得移除监听。
  • 使用方法:在.h中 FOUNDATION_EXPORT + NSString * const +通知名 在.m中赋值。如果在别的页面用到这个通知,使用extern + NSString * const +通知名就可以了。

ps: FOUNDATION_EXPORT 和#define 都能定义常量。FOUNDATION_EXPORT 能够使用==进行判断,效率略高。而且能够隐藏定义细节(就是实现部分不在.中)

示例代码:

  1. FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
  2. FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
  3. /**
  4. * 网络环境发生改变的时候接受的通知
  5. */
  6. NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
  7. /**
  8. * 网络环境发生变化是会发送一个通知,同时携带一组状态数据,根据这个key来去除网络status
  9. */
  10. NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";

6.国际化的问题

我个人认为在开发一个APP之初,就应该考虑国际化的问题,不管日后会不会用到这个功能。当你有了国际化的思想之后,在对控件进行布局的时候,就会比只在一种语言下考虑的更多,这会让一个人对控件布局的视野更加宽阔。好了,这个问题就说这么多。有兴趣的朋友请自行查找相关内容。

7.私有方法

在开发中,难免会使用私有方法来协助我们达到某种目的或获取某个数据。在oc中,我看到很多人都会这样写:- (void)funName {}。个人是不赞成这样写了,除非方法内部使用了self。总之,类似于这样的方法,其实跟我们的业务并没有太大的关系。我进入一个控制器的文件中,目光应该集中在业务代码上才对。

AFNetworking 中,一般都会把私有方法,也可以叫函数,放到头部,你即使不看这些代码,对于整个业务的理解也不会受到影响。所以,这种写法值得推荐。可以适当的使用内联函数,提高效率.

示例代码:

  1. /**
  2. * 把枚举的值转换成字符串
  3. */
  4. NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
  5. switch (status) {
  6. case AFNetworkReachabilityStatusNotReachable:
  7. return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
  8. case AFNetworkReachabilityStatusReachableViaWWAN:
  9. return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
  10. case AFNetworkReachabilityStatusReachableViaWiFi:
  11. return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
  12. case AFNetworkReachabilityStatusUnknown:
  13. default:
  14. return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
  15. }
  16. }
  17. - (NSString *)AFStringFromNetworkReachabilityStatus:(AFNetworkReachabilityStatus)status {
  18. switch (status) {
  19. case AFNetworkReachabilityStatusNotReachable:
  20. return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
  21. case AFNetworkReachabilityStatusReachableViaWWAN:
  22. return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
  23. case AFNetworkReachabilityStatusReachableViaWiFi:
  24. return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
  25. case AFNetworkReachabilityStatusUnknown:
  26. default:
  27. return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
  28. }
  29. }

8.SCNetworkReachabilityRef(网络监控核心实现)

SCNetworkReachabilityRef 是获取网络状态的核心对象,创建这个对象有两个方法:

  • SCNetworkReachabilityCreateWithName
  • SCNetworkReachabilityCreateWithAddress

我们看看实现网络监控的核心代码:

示例代码:

  1. - (void)startMonitoring {
  2. [self stopMonitoring];
  3. if (!self.networkReachability) {
  4. return;
  5. }
  6. __weak __typeof(self)weakSelf = self;
  7. AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
  8. __strong __typeof(weakSelf)strongSelf = weakSelf;
  9. strongSelf.networkReachabilityStatus = status;
  10. if (strongSelf.networkReachabilityStatusBlock) {
  11. strongSelf.networkReachabilityStatusBlock(status);
  12. }
  13. };
  14. SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
  15. SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
  16. SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
  17. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
  18. SCNetworkReachabilityFlags flags;
  19. if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
  20. AFPostReachabilityStatusChange(flags, callback);
  21. }
  22. });
  23. }

上边的方法中涉及了一些 CoreFoundation 的知识,我们来看看:

SCNetworkReachabilityContext点进去,会发现这是一个结构体,一般c语言的结构体是对要保存的数据的一种描述

示例代码:

  1. typedef struct {
  2. CFIndex version;
  3. void * __nullable info;
  4. const void * __nonnull (* __nullable retain)(const void *info);
  5. void (* __nullable release)(const void *info);
  6. CFStringRef __nonnull (* __nullable copyDescription)(const void *info);
  7. } SCNetworkReachabilityContext;
  1. 第一个参数接受一个signed long 的参数
  2. 第二个参数接受一个void * 类型的值,相当于oc的id类型,void * 可以指向任何类型的参数
  3. 第三个参数 是一个函数 目的是对info做retain操作
  4. 第四个参数是一个函数,目的是对info做release操作
  5. 第五个参数是 一个函数,根据info获取Description字符串

设置网络监控分为下边几个步骤:

1.我们先新建上下文

  1. SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};

2.设置回调

  1. SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);

3.加入RunLoop池

  1. SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

9.键值依赖

注册键值依赖,这个可能大家平时用的比较少。可以了解一下。举个例子:

比如说一个类User中有两个属性

还有一个卡片的类card

我们写一个info的setter 和 getter 方法,



这么做的目的是,如果我监听info这个属性,当user中的name或者age有一个改变了,能够出发info的这个监听事件。

示例代码:

  1. @interface User :NSObject
  2. @property (nonatomic,copy)NSString *name;
  3. @property (nonatomic,assign)NSUInteger age;
  4. @end
  5. @interface card :NSObject
  6. @property (nonatomic,copy)NSString *info;
  7. @property (nonatomic,strong)User *user;
  8. @end
  9. @implementation card
  10. - (NSString *)info {
  11. return [NSString stringWithFormat:@"%@/%lu",_user.name,(unsigned long)_user.age];
  12. }
  13. - (void)setInfo:(NSString *)info {
  14. NSArray *array = [info componentsSeparatedByString:@"/"];
  15. _user.name = array[0];
  16. _user.age = [array[1] integerValue];
  17. }
  18. + (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
  19. NSSet * keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
  20. NSArray * moreKeyPaths = nil;
  21. if ([key isEqualToString:@"info"])
  22. {
  23. moreKeyPaths = [NSArray arrayWithObjects:@"user.name", @"user.age", nil];
  24. }
  25. if (moreKeyPaths)
  26. {
  27. keyPaths = [keyPaths setByAddingObjectsFromArray:moreKeyPaths];
  28. }
  29. return keyPaths;
  30. }
  31. @end

10.HTTP

  1. HTTP协议用于客户端和服务器端之间的通信
  2. 通过请求和相应的交换达成通信
  3. HTTP是不保存状态的协议
    • HTTP自身不会对请求和相应之间的通信状态进行保存。什么意思呢?就是说,当有新的请求到来的时候,HTTP就会产生新的响应,对之前的请求和响应的保温信息不做任何存储。这也是为了快速的处理事务,保持良好的可伸展性而特意设计成这样的。
  4. 请求URI定位资源
    • URI算是一个位置的索引,这样就能很方便的访问到互联网上的各种资源。
  5. 告知服务器意图的HTTP方法
    • ①GET: 直接访问URI识别的资源,也就是说根据URI来获取资源。
    • ②POST: 用来传输实体的主体。
    • ③PUT: 用来传输文件。
    • ④HEAD: 用来获取报文首部,和GET方法差不多,只是响应部分不会返回主体内容。
    • ⑤DELETE: 删除文件,和PUT恰恰相反。按照请求的URI来删除指定位置的资源。
    • ⑥OPTIONS: 询问支持的方法,用来查询针对请求URI指定的资源支持的方法。
    • ⑦TRACE: 追踪路径,返回服务器端之前的请求通信环信息。
    • ⑧CONNECT: 要求用隧道协议连接代理,要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。SSL(Secure Sockets Layer)和TLS(Transport Layer Security)就是把通信内容加密后进行隧道传输的。
  6. 管线化让服务器具备了相应多个请求的能力
  7. Cookie让HTTP有迹可循

11.HTTPS

HTTPS是一个通信安全的解决方案,可以说相对已经非常安全。为什么它会是一个很安全的协议呢?下边会做出解释。大家可以看看这篇文章,解释的很有意思 。《简单粗暴系列之HTTPS原理》.

HTTP + 加密 + 认证 + 完整性保护 = HTTPS

其实HTTPS是身披SSL外壳的HTTP,这句话怎么理解呢?

大家应该都知道HTTP是应用层的协议,但HTTPS并非是应用层的一种新协议,只是HTTP通信接口部分用SSL或TLS协议代替而已。

通常 HTTP 直接和TCP通信,当使用SSL时就不同了。要先和SSL通信,再由SSL和TCP通信。

这里再说一些关于加密的题外话:

现如今,通常加密和解密的算法都是公开的。举个例子: a * b = 200,加入a是你知道的密码,b是需要被加密的数据,200 是加密后的结果。那么这里这个*号就是一个很简单的加密算法。这个算法是如此简单。但是如果想要在不知道a和b其中一个的情况下进行破解也是很困难的。就算我们知道了200 然后得到a b 这个也很难。假设知道了密码a 那么b就很容易算出b = 200 / a 。

实际中的加密算法比这个要复杂的多。

介绍两种常用加密方法:

  1. 共享密钥加密

  2. 公开密钥加密

共享密钥加密就是加密和解密通用一个密钥,也称为对称加密。优点是加密解密速度快,缺点是一旦密钥泄露,别人也能解密数据。

公开密钥加密恰恰能解决共享密钥加密的困难,过程是这样的:

  • ①发文方使用对方的公开密钥进行加密

  • ②接受方在使用自己的私有密钥进行解密

关于公开密钥,也就是非对称加密 可以看看这篇文章 RSA算法原理

原理都是一样的,这个不同于刚才举得a和b的例子,就算知道了结果和公钥,破解出被机密的数据是非常难的。这里边主要涉及到了复杂的数学理论。

HTTPS采用混合加密机制

HTTPS采用共享密钥加密和公开密钥加密两者并用的混合加密机制。

注意黄色的部分,这个指明了,我们平时使用的一个场景。这篇文章会很长,不仅仅是为了解释HTTPS,还为了能够增加记忆,当日后想看看的时候,就能通过读这边文章想起大部分的HTTPS的知识。下边解释一些更加详细的HTTPS过程。

12.如何获取证书中的PublicKey

  1. // 在证书中获取公钥
  2. static id AFPublicKeyForCertificate(NSData *certificate) {
  3. id allowedPublicKey = nil;
  4. SecCertificateRef allowedCertificate;
  5. SecCertificateRef allowedCertificates[1];
  6. CFArrayRef tempCertificates = nil;
  7. SecPolicyRef policy = nil;
  8. SecTrustRef allowedTrust = nil;
  9. SecTrustResultType result;
  10. // 1. 根据二进制的certificate生成SecCertificateRef类型的证书
  11. // NSData *certificate 通过CoreFoundation (__bridge CFDataRef)转换成 CFDataRef
  12. // 看下边的这个方法就可以知道需要传递参数的类型
  13. /*
  14. SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef __nullable allocator,
  15. CFDataRef data) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0);
  16. */
  17. allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
  18. // 2.如果allowedCertificate为空,则执行标记_out后边的代码
  19. __Require_Quiet(allowedCertificate != NULL, _out);
  20. // 3.给allowedCertificates赋值
  21. allowedCertificates[0] = allowedCertificate;
  22. // 4.新建CFArra: tempCertificates
  23. tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
  24. // 5. 新建policy为X.509
  25. policy = SecPolicyCreateBasicX509();
  26. // 6.创建SecTrustRef对象,如果出错就跳到_out标记处
  27. __Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
  28. // 7.校验证书的过程,这个不是异步的。
  29. __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
  30. // 8.在SecTrustRef对象中取出公钥
  31. allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
  32. _out:
  33. if (allowedTrust) {
  34. CFRelease(allowedTrust);
  35. }
  36. if (policy) {
  37. CFRelease(policy);
  38. }
  39. if (tempCertificates) {
  40. CFRelease(tempCertificates);
  41. }
  42. if (allowedCertificate) {
  43. CFRelease(allowedCertificate);
  44. }
  45. return allowedPublicKey;
  46. }

在二进制的文件中获取公钥的过程是这样

  • ① NSData *certificate -> CFDataRef -> (SecCertificateCreateWithData) -> SecCertificateRef allowedCertificate
  • ②判断SecCertificateRef allowedCertificate 是不是空,如果为空,直接跳转到后边的代码
  • ③allowedCertificate 保存在allowedCertificates数组中
  • ④allowedCertificates -> (CFArrayCreate) -> SecCertificateRef allowedCertificates[1]
  • ⑤根据函数SecPolicyCreateBasicX509() -> SecPolicyRef policy
  • ⑥SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust) -> 生成SecTrustRef allowedTrust
  • ⑦SecTrustEvaluate(allowedTrust, &result) 校验证书
  • ⑧(__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust) -> 得到公钥id allowedPublicKey

这个过程我们平时也不怎么用,了解下就行了,真需要的时候知道去哪里找资料就行了。

这里边值得学习的地方是:

__Require_Quiet 和 __Require_noErr_Quiet 这两个宏定义。

我们看看他们内部是怎么定义的



可以看出这个宏的用途是:当条件返回false时,执行标记以后的代码



可以看出这个宏的用途是:当条件抛出异常时,执行标记以后的代码

这样就有很多使用场景了。当必须要对条件进行判断的时候,我们有下边几种方案了

  1. #ifdef 这个是编译特性

  2. if else 代码层次的判断

  3. __Require_XXX



_out 就是一个标记,这段代码__Require_Quiet 到_out之间的代码不会执行

13.URL编码

关于什么叫URI编码和为什么要编码,请看我转载的这篇文章url 编码(percentcode 百分号编码)

根据RFC 3986的规定:URL百分比编码的保留字段分为:

  • ':' '#' '[' ']' '@' '?' '/'
  • '!' '$' '&' ''' '(' ')' '*' '+' ',' ';' '='

在对查询字段百分比编码时,'?'和'/'可以不用编码,其他的都要进行编码。我记得在使用支付宝支付时,在对数据进行URL编码时要求编码'/'.

  1. NSString * AFPercentEscapedStringFromString(NSString *string) {
  2. static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
  3. static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
  4. // '?'和'/'在query查询允许不被转译,因此!$&'()*+,;=和:#[]@都要被转译,也就是在URLQueryAllowedCharacterSet中删除掉这些字符
  5. NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
  6. [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
  7. // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
  8. // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
  9. static NSUInteger const batchSize = 50;
  10. NSUInteger index = 0;
  11. NSMutableString *escaped = @"".mutableCopy;
  12. while (index < string.length) {
  13. //http://www.jianshu.com/p/eb03e20f7b1c
  14. #pragma GCC diagnostic push
  15. #pragma GCC diagnostic ignored "-Wgnu"
  16. NSUInteger length = MIN(string.length - index, batchSize);
  17. #pragma GCC diagnostic pop
  18. NSRange range = NSMakeRange(index, length);
  19. // To avoid breaking up character sequences such as
  20. AFNetworking 3.0 源码解读 总结(干货)(上)的更多相关文章

      1. AFNetworking 3.0 源码解读 总结(干货)(下)
      1. 承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...

      1. AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking
      1. AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...

      1. AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking
      1. 我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3UIKit中的分类.UIAct ...

      1. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager
      1. 让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

      1. AFNetworking 3.0 源码解读(八)之 AFImageDownloader
      1. AFImageDownloader 这个类对写DownloadManager有很大的借鉴意义.在平时的开发中,当我们使用UIImageView加载一个网络上的图片时,其原理就是把图片下载下来,然后再赋 ...

      1. AFNetworking 3.0 源码解读(七)之 AFAutoPurgingImageCache
      1. 这篇我们就要介绍AFAutoPurgingImageCache这个类了.这个类给了我们临时管理图片内存的能力. 前言 假如说我们要写一个通用的网络框架,除了必备的请求数据的方法外,必须提供一个下载器来 ...

      1. AFNetworking 3.0 源码解读(六)之 AFHTTPSessionManager
      1. AFHTTPSessionManager相对来说比较好理解,代码也比较短.但却是我们平时可能使用最多的类. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilit ...

      1. AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization
      1. 这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...

      1. AFNetworking 3.0 源码解读(四)之 AFURLResponseSerialization
      1. 本篇是AFNetworking 3.0 源码解读的第四篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3 ...

      1. AFNetworking 3.0 源码解读(五)之 AFURLSessionManager
      1. 本篇是AFNetworking 3.0 源码解读的第五篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3 ...

    1. 随机推荐

        1. 几个比较”有意思“的JS脚本
        1. 1.获取内网和公网真实IP地址(引用地址) <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...

        1. HTML骨架结构
        1. 前面的话   一个完整的HTML文档必须包含3个部分:文档声明.文档头部和文档主体.而正是它们构成了HTML的骨架结构.前面已经分别介绍过文档声明和文档头部,本文将详细介绍构成HTML骨架结构的基础元 ...

        1. UE4新手引导之下载和安装虚幻4游戏引擎
        1. 1) 进入虚幻4的官方主页(https://www.unrealengine.com/) 这里你可以获得关于虚幻4的最新资讯,包括版本更新.博客更新.新闻和商城等.自2015年起,该引擎已经提供免费下 ...

        1. C++随笔:.NET CoreCLR之GC探索(4)
        1. 今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...

        1. Android如何制作漂亮的自适布局的键盘
        1. 最近做了个自定义键盘,但面对不同分辨率的机型其中数字键盘不能根据界面大小自已铺满,但又不能每种机型都做一套吧,所以要做成自适应,那这里主讲思路. 这里最上面的titlebar高度固定,下面输入的金额高 ...

        1. Atiti.大企业病与小企业病 大公司病与小公司病
        1. Atiti.大企业病与小企业病 大公司病与小公司病 1. 大企业病,一般会符合机构臃肿 .多重领导 .人才流失的特点.1 2. 大企业病避免方法1 3. 小企业病 1 3.1.1. 表现1 4. 如何 ...

        1. Spark的StandAlone模式原理和安装、Spark-on-YARN的理解
        1. Spark是一个内存迭代式运算框架,通过RDD来描述数据从哪里来,数据用那个算子计算,计算完的数据保存到哪里,RDD之间的依赖关系.他只是一个运算框架,和storm一样只做运算,不做存储. Spark ...

        1. 完整部署CentOS7.2+OpenStack+kvm 云平台环境(1)--基础环境搭建
        1. 公司在IDC机房有两台很高配置的服务器,计划在上面部署openstack云平台虚拟化环境,用于承载后期开发测试和其他的一些对内业务.以下对openstack的部署过程及其使用做一详细介绍,仅仅依据本人 ...

        1. C#与yaml解析
        1. YAML 官方网站称 YAML 是"一种所有编程语言可用的友好的数据序列化标准".YAML Ain't Markup Language,和GNU一样,YAML是一个递归着说&quo ...

        1. .NET应用程序与数据库交互的若干问题
        1. 我们知道,在应用程序中与数据库进行交互是一个比较耗时的过程,首先应用程序需要与应用程序建立连接,然后将请求发送到数据库,数据库执行操作,然后将结果集返回.所以在程序中,要尽量晚的与数据库建立连接,并且 ...