AFNetworking源码拾遗

一句话简介:最著名的OC开源网络库。

Github: 传送门

PS: 本拾遗系列文章只专注于代码以及工程层面知识点拾遗,架构层面作者文章已经进行了详细的讲解。

1. @import和modulemap

首先OC中的@import以及Swift中的import其实都是基于modulemap实现的。

2. 各种标记

  • __unused: 避免因变量声明未使用造成的警告。
  • ARC相关(如__autoreleasing)参考: iOS开发ARC内存管理技术要点
  • NS_DESIGNATED_INITIALIZER 声明了designated初始化方法后,其余初始化方法如果没有调用designated初始化会有警告提示,具体可以参考: Xcode 6 Objective-C Modernization
  • DEPRECATED_ATTRIBUTE(过期)、NS_SWIFT_NOTHROW(一些便于OC迁移Swift的标记)等

3. 宏

  • FOUNDATION_EXPORT: 对于extern的兼容性封装,根据不同的平台,转化为对应的extern形式。
  • NS_ASSUME_NONNULL_BEGIN、NS_ASSUME_NONNULL_END: 在宏范围内的变量、参数、返回值等都默认添加nonnull。

4. queryString转换的经典代码

经常被摘出来放到自己项目中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
Returns a percent-escaped string following RFC 3986 for a query string key or value.
RFC 3986 states that the following characters are "reserved" characters.
- General Delimiters: ":", "#", "[", "]", "@", "?", "/"
- Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="

In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
should be percent-escaped in the query string.
- parameter string: The string to be percent-escaped.
- returns: The percent-escaped string.
*/
NSString * AFPercentEscapedStringFromString(NSString *string) {
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";

NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];

// FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
// return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
// 以下为针对非单字节字符的处理

static NSUInteger const batchSize = 50;

NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy;

while (index < string.length) {
NSUInteger length = MIN(string.length - index, batchSize);
NSRange range = NSMakeRange(index, length);

// To avoid breaking up character sequences such as 👴🏻👮🏽
range = [string rangeOfComposedCharacterSequencesForRange:range];

NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
[escaped appendString:encoded];

index += range.length;
}

return escaped;
}

5. 架构简图

AFNetworking.png