afnetworking 3.0+ maxconcurrentycsb operationcountt设置多少合适

临时&改造&(基于AFNetworking的再封装)
这种写法太繁琐了 &这个为临时记录 要睡觉了
对象管的太严,我已经改成ajax的命名方式和简单的写法,有时间了分享出来;
get:@"api接口" parameters:nil success:^(id responseObject){
NSDictionary *dict =
NSLog(@"返回内容:%@",dict);
& & } failure:^(NSError *error){
& NSLog(@"返回内容:%@",error);
HttpRequest.h
//& Created by
hanwenbo on 16/5/29.
//& Copyright &
2016年 WenshuaiTechnology. All rights reserved.
//& Author :
天津文率科技有限公司,韩文博
//& WeChat :
wenshuaikeji & bowenhan
//& Email :
//& Website :
//& WeiBo :
@interface UploadParam : NSObject
@property (nonatomic, strong) NSData *
@property (nonatomic, copy)
NSString *
@property (nonatomic, copy)
NSString *
@property (nonatomic, copy)
NSString *mimeT
typedef NS_ENUM(NSUInteger,HttpRequestType)
& HttpRequestTypeGet = 0,
& HttpRequestTypePost
@interface HttpRequest : NSObject
+ (instancetype)sharedI
+ (void)get:(NSString *)URLString
parameters:(id)parameters success:(void
(^)(id responseObject))success failure:(void (^)(NSError *error))
+ (void)post:(NSString *)URLString
parameters:(id)parameters
& & success:(void (^)(id responseObject))success
& & failure:(void (^)(NSError *error))
+ (void)requestWithURLString:(NSString
*)URLString
parameters:(id)parameters
& & type:(HttpRequestType)type
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))
//& Created by
hanwenbo on 16/5/29.
//& Copyright &
2016年 WenshuaiTechnology. All rights reserved.
//& Author :
天津文率科技有限公司,韩文博
//& WeChat :
wenshuaikeji & bowenhan
//& Email :
//& Website :
//& WeiBo :
#import "HttpRequest.h"
@implementation HttpRequest
static id _instance = nil;
+ (instancetype)sharedInstance
[[self alloc] init];
+ (instancetype)allocWithZone:(struct
_NSZone *)zone
dispatch_once_t onceT
& dispatch_once(&onceToken,
_instance =
[super allocWithZone:zone];
_instance;
- (instancetype)init {
dispatch_once_t onceT
& dispatch_once(&onceToken,
_instance =
[super init];
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
[manager startMonitoring];
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus
& & switch (status) {
& case AFNetworkReachabilityStatusUnknown:
// 位置网络
NSLog(@"位置网络");
& case AFNetworkReachabilityStatusNotReachable:
// 无法联网
NSLog(@"无法联网");
& case AFNetworkReachabilityStatusReachableViaWiFi:
// 手机自带网络
NSLog(@"当前使用的是2G/3G/4G网络");
& case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(@"当前在WIFI网络下");
_instance;
#pragma mark --
GET请求 --
+ (void)get:(NSString *)URLString
parameters:(id)parameters
& success:(void
(^)(id))success
& failure:(void
(^)(NSError
*))failure {
& AFHTTPRequestOperationManager *manager
= [AFHTTPRequestOperationManager
& //设置请求头
& [manager.requestSerializer setValue: uuid forHTTPHeaderField:@"device_identification"];
& [manager.requestSerializer setValue: user[@"id"] forHTTPHeaderField:@"uid"];
& [manager.requestSerializer setValue: user[@"access_token"] forHTTPHeaderField:@"access_token"];
& manager.responseSerializer =
[AFHTTPResponseSerializer serializer];
manager.operationQueue.maxConcurrentOperationCount = 5;
& manager.requestSerializer.timeoutInterval = 30;
& [manager GET:[NSString stringWithFormat:@"%@%@",api_host,URLString]
parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success(responseObject);
& } failure:^(AFHTTPRequestOperation *operation, NSError
if (failure) {
& & failure(error);
#pragma mark --
POST请求 --
+ (void)post:(NSString *)URLString
parameters:(id)parameters
& & success:(void (^)(id))success
& & failure:(void (^)(NSError *))failure {
& AFHTTPRequestOperationManager *manager
= [AFHTTPRequestOperationManager
& //设置请求头
& [manager.requestSerializer setValue: uuid forHTTPHeaderField:@"device_identification"];
& [manager.requestSerializer setValue: user[@"id"] forHTTPHeaderField:@"uid"];
& [manager.requestSerializer setValue: user[@"access_token"] forHTTPHeaderField:@"access_token"];
& [manager POST: [NSString stringWithFormat:@"%@%@",api_host,URLString]& parameters:parameters
success:^(AFHTTPRequestOperation
*operation, id
responseObject) {
if (success) {
success(responseObject);
& } failure:^(AFHTTPRequestOperation *operation,
NSError *error) {
if (failure) {
& & failure(error);
#pragma mark --
POST/GET网络请求 --
+ (void)requestWithURLString:(NSString *)URLString
parameters:(id)parameters
& & type:(HttpRequestType)type
success:(void (^)(id))success
failure:(void (^)(NSError *))failure {
& AFHTTPRequestOperationManager *manager
= [AFHTTPRequestOperationManager
& manager.responseSerializer =
[AFHTTPResponseSerializer
serializer];
& //设置请求头
& manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
& manager.requestSerializer =
[AFJSONRequestSerializer
serializer];
& manager.responseSerializer =
[AFJSONResponseSerializer
serializer];
& [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
& [manager.requestSerializer setValue:@"application/ charset=utf-8" forHTTPHeaderField:@"Content-Type"];
& [manager.requestSerializer setValue: uuid forHTTPHeaderField:@"device_identification"];
& [manager.requestSerializer setValue: user[@"id"] forHTTPHeaderField:@"uid"];
& [manager.requestSerializer setValue: user[@"access_token"] forHTTPHeaderField:@"access_token"];
case HttpRequestTypeGet:
& & [manager GET:URLString parameters:parameters
success:^(AFHTTPRequestOperation
*operation, id
responseObject) {
& if (success) {
success(responseObject);
& & } failure:^(AFHTTPRequestOperation *operation, NSError
& if (failure) {
failure(error);
& & break;
case HttpRequestTypePost:
& & [manager POST:
URLString& parameters:parameters
success:^(AFHTTPRequestOperation
*operation, id
responseObject) {
& if (success) {
success(responseObject);
& & } failure:^(AFHTTPRequestOperation *operation, NSError
& if (failure) {
failure(error);
& & break;
#pragma mark -- 上传图片 --
(void)uploadWithURLString:(NSString *)URLString
& parameters:(id)parameters
& uploadParam:(UploadParam
*)uploadParam
success:(void (^)())success
failure:(void (^)(NSError *))failure {
& AFHTTPRequestOperationManager *manager =
[AFHTTPRequestOperationManager manager];
& manager.responseSerializer =
[AFHTTPResponseSerializer serializer];
& [manager POST: URLString&
parameters:parameters success:^(AFHTTPRequestOperation *operation,
id responseObject) {
(success) {
success(responseObject);
& } failure:^(AFHTTPRequestOperation *operation,
NSError *error) {
(failure) {
& & failure(error);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。iOS开发之网络请求(基于AFNetworking的再封装)-android100学习网
iOS开发之网络请求(基于AFNetworking的再封装)
最近一直很忙也没有什么时间写博客了。放假了休息一下,就写一篇博客来总结一下最近做项目中出现过的问题吧!!! 首先,在项目中我的起到了什么作用,无非就是把美工(UI设计师)给我们的图显
最近一直很忙也没有什么时间写博客了。放假了休息一下,就写一篇博客来总结一下最近做项目中出现过的问题吧!!!
首先,在项目中我的起到了什么作用,无非就是把美工(UI设计师)给我们的图显示出来,然后再和服务器进行交互。
那个我们和服务器怎么交互呢?最简单的方式就是说话呗,但是我们要跟服务器说话必须通过我们彼此能听的懂的话来交流,也就需要制定很多的协议了(http,tcp,udp等,这个有兴趣的朋友可以了解一下网络协议的东西)。但是我平常最常使用的还是http协议。
/li0803/archive//1324746.html 这篇博客详细讲解了http协议的东西(我能说是我随便百度了一篇博客吗?)
然后github上的AFNetworking应该现在是应用的最广泛的网络请求三方库了吧。那么今天就来说一下AFNetworing。
既然人家已经封装的这么好了,我们为什么还要多此一举再封装呢?
那现在就来说一下再封装的意义是什么?
最重要的意义差不多就是统一接口(这个也是封装的一个作用,如果不了解封装的同学可以去看看封装的用处,是个提高效率的非常有效的办法),这一点要是再多人项目中尤其能体现出来,我的一个同事用的是系统自带的MKNetworking,很多人可能听都没听过,他虽然用的很好,我也能看的懂,但是还是感觉看起来很难受,因为我根本不想看到他的具体用法和实现是什么样子的(虽然真正敲起来可能也只是多了两行代码而已),只需要调一个接口就什么都用了不就好了,为什么还要敲那么多重复的代码呢(Don't repeat yourself)?
好,下面我就来对AFNetworking再封装:
首先,还是说一下封装的事情,如果是你自己用,那么你可以随便写一写,因为你不用注释也能看的懂。但是如果是给几个人用,你可以直接告诉他们,或者说是写一个比较详细的注释,以便他们日后忘记了看一下就知道每个参数的意义是什么了!!!
那么我在网络请求的时候究竟最常用的网络请求有哪些呢?
我最常用到的就是get,post和upload了。(这几中请求方式也可以去了解一下他们的区别)
说了这么多的废话了来点干货。
@interface UploadParam : NSObject
图片的二进制数据
@property (nonatomic, strong) NSData *
服务器对应的参数名称
@property (nonatomic, copy) NSString *
文件的名称(上传到服务器后,服务器保存的文件名)
@property (nonatomic, copy) NSString *
文件的MIME类型(image/png,image/jpg等)
@property (nonatomic, copy) NSString *mimeT
@class UploadP
网络请求类型
typedef NS_ENUM(NSUInteger,HttpRequestType) {
HttpRequestTypeGet = 0,
HttpRequestTypePost
@interface HttpRequest : NSObject
发送get请求
@param URLString
请求的网址字符串
@param parameters 请求的参数
@param success
请求成功的回调
@param failure
请求失败的回调
+ (void)getWithURLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))
发送post请求
@param URLString
请求的网址字符串
@param parameters 请求的参数
@param success
请求成功的回调
@param failure
请求失败的回调
+ (void)postWithURLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))
发送网络请求
@param URLString
请求的网址字符串
@param parameters
请求的参数
@param type
请求的类型
@param resultBlock 请求的结果
+ (void)requestWithURLString:(NSString *)URLString
parameters:(id)parameters
type:(HttpRequestType)type
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))
@param URLString
上传图片的网址字符串
@param parameters
上传图片的参数
@param uploadParam 上传图片的信息
@param success
上传成功的回调
@param failure
上传失败的回调
+ (void)uploadWithURLString:(NSString *)URLString
parameters:(id)parameters
uploadParam:(UploadParam *)uploadParam
success:(void (^)())success
failure:(void (^)(NSError *error))
#import "HttpRequest.h"
#import "AFNetworking.h"
#import "UploadParam.h"
@implementation HttpRequest
#pragma mark -- GET请求 --
+ (void)getWithURLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(id))success
failure:(void (^)(NSError *))failure {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
可以接受的类型
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
请求队列的最大并发数
manager.operationQueue.maxConcurrentOperationCount = 5;
请求超时的时间
manager.requestSerializer.timeoutInterval = 5;
[manager GET:URLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id
_Nullable responseObject) {
if (success) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
#pragma mark -- POST请求 --
+ (void)postWithURLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(id))success
failure:(void (^)(NSError *))failure {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id
_Nullable responseObject) {
if (success) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
#pragma mark -- POST/GET网络请求 --
+ (void)requestWithURLString:(NSString *)URLString
parameters:(id)parameters
type:(HttpRequestType)type
success:(void (^)(id))success
failure:(void (^)(NSError *))failure {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
switch (type) {
case HttpRequestTypeGet:
[manager GET:URLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id
_Nullable responseObject) {
if (success) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
case HttpRequestTypePost:
[manager POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id
_Nullable responseObject) {
if (success) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
#pragma mark -- 上传图片 --
+ (void)uploadWithURLString:(NSString *)URLString
parameters:(id)parameters
uploadParam:(UploadParam *)uploadParam
success:(void (^)())success
failure:(void (^)(NSError *))failure {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:URLString parameters:parameters constructingBodyWithBlock:^(id&AFMultipartFormData&
_Nonnull formData) {
[formData appendPartWithFileData:uploadParam.data name:uploadParam.name fileName:uploadParam.filename mimeType:uploadParam.mimeType];
} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id
_Nullable responseObject) {
if (success) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
} 我把我的demo也传到我的空间,欢迎大家下载。我用的是cocospod三方库,如果下载了不能使用的,也可以联系我!
来自: /wuhongxing/p/5094634.html承接上一篇
21.网络服务类型NSURLRequestNetworkServiceType
示例代码:
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
NSURLNetworkServiceTypeDefault = 0,
// Standard internet traffic
NSURLNetworkServiceTypeVoIP = 1,
// Voice over IP control traffic
NSURLNetworkServiceTypeVideo = 2,
// Video traffic
NSURLNetworkServiceTypeBackground = 3, // Background traffic
NSURLNetworkServiceTypeVoice = 4
// Voice data
可以通过这个值来指定当前的网络类型,系统会跟据制定的网络类型对很多方面进行优化,这个就设计到很细微的编程技巧了,可作为一个优化的点备用。
22.Authorization字段
在请求头中可以添加Authorization字段。
Authorization: Basic YWRtaW46YWRtaW4= 其中Basic表示基础认证,当然还有其他认证,如果感兴趣,可以看看本文开始提出的那本书。后边的YWRtaW46YWRtaW4= 是根据username:password 拼接后然后在经过Base64编码后的结果。
如果header中有 Authorization这个字段,那么服务器会验证用户名和密码,如果不正确的话会返回401错误。
23.使用流写数据
下边的代码可以说是使用流写数据的经典案例。可直接拿来使用。
示例代码:
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
writingStreamContentsToFile:(NSURL *)fileURL
completionHandler:(void (^)(NSError *error))handler
NSParameterAssert(request.HTTPBodyStream);
NSParameterAssert([fileURL isFileURL]);
// 加上上边的两个判断,下边的这些代码就是把文件写到另一个地方的典型使用方法了
NSInputStream *inputStream = request.HTTPBodyS
NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:fileURL append:NO];
__block NSError *error =
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
// 读取数据
while ([inputStream hasBytesAvailable] && [outputStream hasSpaceAvailable]) {
uint8_t buffer[1024];
NSInteger bytesRead = [inputStream read:buffer maxLength:1024];
if (inputStream.streamError || bytesRead & 0) {
error = inputStream.streamE
NSInteger bytesWritten = [outputStream write:buffer maxLength:(NSUInteger)bytesRead];
if (outputStream.streamError || bytesWritten & 0) {
error = outputStream.streamE
if (bytesRead == 0 && bytesWritten == 0) {
[outputStream close];
[inputStream close];
if (handler) {
dispatch_async(dispatch_get_main_queue(), ^{
handler(error);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
mutableRequest.HTTPBodyStream =
return mutableR
24.NSIndexSet
定义:NSIndexSet是一个有序的,唯一的,无符号整数的集合。
我们先看个例子:
NSMutableIndexSet *indexSetM = [NSMutableIndexSet indexSet];
[indexSetM addIndex:19];
[indexSetM addIndex:4];
[indexSetM addIndex:6];
[indexSetM addIndex:8];
[indexSetM addIndexesInRange:NSMakeRange(20, 10)];
[indexSetM enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@&%lu&,idx);
打印结果如下:
11:39:00.826 xxxx[] 4
11:39:00.827 xxxx[] 6
11:39:00.827 xxxx[] 8
11:39:00.827 xxxx[] 19
11:39:00.827 xxxx[] 20
11:39:00.828 xxxx[] 21
11:39:00.828 xxxx[] 22
11:39:00.828 xxxx[] 23
11:39:00.828 xxxx[] 24
11:39:00.828 xxxx[] 25
11:39:00.828 xxxx[] 26
11:39:00.828 xxxx[] 27
11:39:00.828 xxxx[] 28
11:39:00.829 xxxx[] 29
这充分说明了一下几点
它是一个无符号整数的集合
用addIndex方法可以添加单个整数值,使用addIndexesInRange可以添加一个范围,比如NSMakeRange(20, 10) 取20包括20后边十个整数
唯一性,集合内的整数不会重复出现
具体用法就不再次做详细的解释了,有兴趣的朋友可以看看这篇文章:
25.NSUnderlyingErrorKey优先错误
当出现可能会有两个错误的情况下,可以考虑使用NSUnderlyingErrorKey处理这种情况。
示例代码:
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
if (!error) {
return underlyingE
if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) {
NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy];
mutableUserInfo[NSUnderlyingErrorKey] = underlyingE
return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];
26.NSJSONReadingOptions
这个选项可以设置json的读取选项,我们点进去可以看到:
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
NSJSONReadingMutableContainers = (1UL && 0),
NSJSONReadingMutableLeaves = (1UL && 1),
NSJSONReadingAllowFragments = (1UL && 2)
} NS_ENUM_AVAILABLE(10_7, 5_0);
NSJSONReadingMutableContainers 这个解析json成功后返回一个容器
NSJSONReadingMutableLeaves 返回中的json对象中字符串为NSMutableString
NSJSONReadingAllowFragments 允许JSON字符串最外层既不是NSArray也不是NSDictionary,但必须是有效的JSON Fragment。例如使用这个选项可以解析 @“123” 这样的字符串
我们举个例子说明一下NSJSONReadingMutableContainers:
NSString *str = @&{\&name\&:\&zhangsan\&}&;
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
// 应用崩溃,不选用NSJSONReadingOptions,则返回的对象是不可变的,NSDictionary
[dict setObject:@&male& forKey:@&sex&];
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
// 没问题,使用NSJSONReadingMutableContainers,则返回的对象是可变的,NSMutableDictionary
[dict setObject:@&male& forKey:@&sex&];
NSLog(@&%@&, dict);
如果服务器返回的json的最外层并不是以NSArray 或者 NSDictionary ,而是一个有效的json fragment ,比如 。 那么我们使用NSJSONReadingAllowFragments这个选项也能够解析出来。
27.图片解压杂谈
AFJSONResponseSerializer使用系统内置的NSJSONSerialization解析json,NSJSON只支持解析UTF8编码的数据(还有UTF-16LE之类的,都不常用),所以要先把返回的数据转成UTF8格式。这里会尝试用HTTP返回的编码类型和自己设置的stringEncoding去把数据解码转成字符串NSString,再把NSString用UTF8编码转成NSData,再用NSJSONSerialization解析成对象返回。
上述过程是NSData-&NSString-&NSData-&NSObject,这里有个问题,如果你能确定服务端返回的是UTF8编码的json数据,那NSData-&NSString-&NSData这两步就是无意义的,而且这两步进行了两次编解码,很浪费性能,所以如果确定服务端返回utf8编码数据,就建议自己再写个JSONResponseSerializer,跳过这两个步骤。
此外AFJSONResponseSerializer专门写了个方法去除NSNull,直接把对象里值是NSNull的键去掉,还蛮贴心,若不去掉,上层很容易忽略了这个数据类型,判断了数据是否nil没判断是否NSNull,进行了错误的调用导致core。
当我们调用UIImage的方法imageWithData:方法把数据转成UIImage对象后,其实这时UIImage对象还没准备好需要渲染到屏幕的数据,现在的网络图像PNG和JPG都是压缩格式,需要把它们解压转成bitmap后才能渲染到屏幕上,如果不做任何处理,当你把UIImage赋给UIImageView,在渲染之前底层会判断到UIImage对象未解压,没有bitmap数据,这时会在主线程对图片进行解压操作,再渲染到屏幕上。这个解压操作是比较耗时的,如果任由它在主线程做,可能会导致速度慢UI卡顿的问题。
AFImageResponseSerializer除了把返回数据解析成UIImage外,还会把图像数据解压,这个处理是在子线程(AFNetworking专用的一条线程,详见AFURLConnectionOperation),处理后上层使用返回的UIImage在主线程渲染时就不需要做解压这步操作,主线程减轻了负担,减少了UI卡顿问题。
具体实现上在AFInflatedImageFromResponseWithDataAtScale里,创建一个画布,把UIImage画在画布上,再把这个画布保存成UIImage返回给上层。只有JPG和PNG才会尝试去做解压操作,期间如果解压失败,或者遇到CMKY颜色格式的jpg,或者图像太大(解压后的bitmap太占内存,一个像素3-4字节,搞不好内存就爆掉了),就直接返回未解压的图像。
另外在代码里看到iOS才需要这样手动解压,MacOS上已经有封装好的对象NSBitmapImageRep可以做这个事。
关于图片解压,还有几个问题不清楚:
1.本来以为调用imageWithData方法只是持有了数据,没有做解压相关的事,后来看到调用堆栈发现已经做了一些解压操作,从调用名字看进行了huffman解码,不知还会继续做到解码jpg的哪一步。
UIImage_jpg
2.以上图片手动解压方式都是在CPU进行的,如果不进行手动解压,把图片放进layer里,让底层自动做这个事,是会用GPU进行的解压的。不知用GPU解压与用CPU解压速度会差多少,如果GPU速度很快,就算是在主线程做解压,也变得可以接受了,就不需要手动解压这样的优化了,不过目前没找到方法检测GPU解压的速度。
28.获取系统版本
#ifndef NSFoundationVersionNumber_iOS_8_0
#define NSFoundationVersionNumber_With_Fixed_9552_bug 1140.11
#define NSFoundationVersionNumber_With_Fixed_9552_bug NSFoundationVersionNumber_iOS_8_0
上边的这个宏的目的是通过NSFoundation的版本来判断当前ios版本,关键是这个宏的调试目标是IOS,来看看系统是怎么定义的:
那么我们就能够联想到,目前我们能够判断系统版本号的方法有几种呢?最少三种:
[UIDevice currentDevice].systemVersion
通过比较Foundation框架的版本号,iOS系统升级的同时Foundation框架的版本也会提高
通过在某系版本中新出现的方法来判断,UIAlertController 这个类是iOS8之后才出现的 NS_CLASS_AVAILABLE_IOS(8_0),如果当前系统版本没有这个类NSClassFromString(@&UIAlertController& == (null),从而判断当前版本是否大于等于iOS8
29.dispatch_queue_create()
AFNetworking中所有的和创建任务相关的事件都放到了一个单例的队列中,我们平时可能会使用这些方法,但还是可能会忽略一些内容,dispatch_queue_create()这个是队列的方法,第一个参数是队列的identifier,第二个参数则表示这个队列是串行队列还是并行队列。
如果第二个参数为DISPATCH_QUEUE_SERIAL或NULL 则表示队列为串行队列。如果为DISPATCH_QUEUE_CONCURRENT则表示是并行队列。
关于队列的小的知识点,参考了这篇文章
30.dispatch_block_t
这个方法还有一个小知识点:dispatch_block_t ,点击去可以看到:
typedef void (^dispatch_block_t)(void);
关于这个Block我们应该注意几点:
非ARC情况下,Block被allocated或者copied到堆后,一定要记得释放它,通过[release]或者Block_release()
非ARC情况下,Block被allocated或者copied到堆后,一定要记得释放它,通过[release]或者Block_release()
31.NSKeyValueObservingOptions
NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后
32.task delegate出发问题
task一共有4个delegate,只要设置了一个,就代表四个全部设置,有时候一些delegate不会被触发的原因在于这四种delegate是针对不同的URLSession类型和URLSessionTask类型来进行响应的,也就是说不同的类型只会触发这些delegate中的一部分,而不是触发所有的delegate。
举例说明如下:
触发NSURLSessionDataDelegate
//使用函数dataTask来接收数据
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
//则NSURLSession部分的代码如下
NSURLSessionConfiguration* ephConfiguration=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession* session=[NSURLSession sessionWithConfiguration:ephConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL* url=[NSURL URLWithString:@&/external_links/01.png&];
NSURLSessionDataTask* dataTask=[session dataTaskWithURL:url];
[dataTask resume];
触发NSURLSessionDownloadDelegate
//使用函数downloadTask来接受数据
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
//则NSURLSession部分的代码如下
NSURLSessionConfiguration* ephConfiguration=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession* session=[NSURLSession sessionWithConfiguration:ephConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL* url=[NSURL URLWithString:@&/external_links/01.png&];
NSURLSessionDownloadTask* dataTask=[session downloadTaskWithURL:url];
[dataTask resume];
这两段代码的主要区别在于NSURLSessionTask的类型的不同,造成了不同的Delegate被触发.
33.@unionOfArrays
tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@&@unionOfArrays.self&];
这么使用之前确实不太知道,如果是我,可能就直接赋值给数组了。?
@distinctUnionOfObjects 清楚重复值
unionOfObjects 保留重复值
34.相对路径(relative)
假如有一个基础路径NSURL *baseURL = [NSURL URLWithString:@&/v1/&];我们暂时命名为baseURL.所谓 相对 肯定跟这个baseURL有关系
我们可以通过 NSURL +URLWithString:relativeToUL:这个方法来获取一个路径,至于怎么使用,我们通过一个例子来说明:
NSURL *baseURL = [NSURL URLWithString:@&/v1/&];
[NSURL URLWithString:@&foo& relativeToURL:baseURL];
// /v1/foo
[NSURL URLWithString:@&foo?bar=baz& relativeToURL:baseURL];
// /v1/foo?bar=baz
[NSURL URLWithString:@&/foo& relativeToURL:baseURL];
[NSURL URLWithString:@&foo/& relativeToURL:baseURL];
// /v1/foo
[NSURL URLWithString:@&/foo/& relativeToURL:baseURL];
[NSURL URLWithString:@&/& relativeToURL:baseURL]; // /
至于 绝对路径 和 相对路径 的定义,使用方法,优缺点,这里就不提了,大家可以自行了解。说一下为什么使用相对路径吧。
在真实开发中,一般都会有一个线上的服务器和一下测试服务器,当然也可能多个。在ios开发中切换开发环境有好几种方法
通过target
自定义一个字段HTTPURL,用它来控制路径
通过相对路径来切换接口
35.dispatch_barrier_async
barrier 这个单词的意思是障碍,拦截的意思,也即是说 dispatch_barrier_async 一定是有拦截事件的作用。
看下边这段代码:
dispatch_queue_t concurrentQueue = dispatch_queue_create(&my.concurrent.queue&, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-1&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-2&);
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@&dispatch-barrier&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-3&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-4&);
打印结果:
16:43:20.554 xxx[] dispatch-1
16:43:20.555 xxx[] dispatch-2
16:43:20.556 xxx[] dispatch-barrier
16:43:20.556 xxx[] dispatch-3
16:43:20.556 xxx[] dispatch-4
这个说明了 dispatch_barrier_async 能够拦截它前边的异步事件,等待两个异步方法都完成之后,调用 dispatch_barrier_async。
我们稍微改动一下:
dispatch_queue_t concurrentQueue = dispatch_queue_create(&my.concurrent.queue&, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-1&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-2&);
dispatch_barrier_sync(concurrentQueue, ^(){
NSLog(@&dispatch-barrier&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-3&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&dispatch-4&);
打印结果:
16:43:20.554 xxx[] dispatch-1
16:43:20.555 xxx[] dispatch-2
16:43:20.556 xxx[] dispatch-barrier
16:43:20.556 xxx[] dispatch-3
16:43:20.556 xxx[] dispatch-4
36.dispatch_sync() 和 dispatch_async()
大概说下 dispatch_sync() 和 dispatch_async() 这两个方法。
示例代码:
dispatch_queue_t concurrentQueue = dispatch_queue_create(&my.concurrent.queue&, DISPATCH_QUEUE_CONCURRENT);
NSLog(@&1&);
dispatch_sync(concurrentQueue, ^(){
NSLog(@&2&);
[NSThread sleepForTimeInterval:5];
NSLog(@&3&);
NSLog(@&4&);
11:50:51.601 xxxx[] 1
11:50:51.601 xxxx[] 2
11:50:56.603 xxxx[] 3
11:50:56.603 xxxx[] 4
dispatch_queue_t concurrentQueue = dispatch_queue_create(&my.concurrent.queue&, DISPATCH_QUEUE_CONCURRENT);
NSLog(@&1&);
dispatch_async(concurrentQueue, ^(){
NSLog(@&2&);
[NSThread sleepForTimeInterval:5];
NSLog(@&3&);
NSLog(@&4&);
11:52:29.022 xxxx[] 1
11:52:29.023 xxxx[] 4
11:52:29.023 xxxx[] 2
11:52:34.029 xxxx[] 3
通过上边的两个例子,我们可以总结出:
dispatch_sync(),同步添加操作。他是等待添加进队列里面的操作完成之后再继续执行
dispatch_async ,异步添加进任务队列,它不会做任何等待
37.NSURLCache
我们简单介绍下NSURLCache。NSURLCache 为您的应用的 URL 请求提供了内存中以及磁盘上的综合缓存机制。网络缓存减少了需要向服务器发送请求的次数,同时也提升了离线或在低速网络中使用应用的体验。当一个请求完成下载来自服务器的回应,一个缓存的回应将在本地保存。下一次同一个请求再发起时,本地保存的回应就会马上返回,不需要连接服务器。NSURLCache 会 自动 且 透明 地返回回应。
为了好好利用 NSURLCache,你需要初始化并设置一个共享的 URL 缓存。在 iOS 中这项工作需要在 -application:didFinishLaunchingWithOptions: 完成,而 OS X 中是在 –applicationDidFinishLaunching::
示例代码:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
NSURLRequest 有个 cachePolicy 属性,我们平时最常用的有四个属性:
NSURLRequestUseProtocolCachePolicy: 对特定的 URL 请求使用网络协议中实现的缓存逻辑。这是默认的策略
NSURLRequestReloadIgnoringLocalCacheData:数据需要从原始地址加载。不使用现有缓存。
NSURLRequestReturnCacheDataElseLoad:无论缓存是否过期,先使用本地缓存数据。如果缓存中没有请求所对应的数据,那么从原始地址加载数据
NSURLRequestReturnCacheDataDontLoad:无论缓存是否过期,先使用本地缓存数据。如果缓存中没有请求所对应的数据,那么放弃从原始地址加载数据,请求视为失败(即:“离线”模式)。
38.@synchronized()锁
synchronized是一种锁,这种锁不管是在oc中还是java中用的都挺多的,而且这种锁锁得是对象。具体原理,可以看这篇文章后边的 参考 那一部分。
总结一下,锁一般用于多线程环境下对数据的操作中。在 AFNetworking 中我们见到了3种不同的锁,分别是:
dispatch_semaphore_wait
@synchronized
39.UIWebView+AFNetworking
UIWebView的这个分类是这几个分类中最让我惊讶的一个。让我真正认识到条条大路通罗马到底是什么意思。有时候人的思想确实会被固有的思维所束缚。这里只是用了UIWebView的loadData:(NSData )data MIMEType:(NSString )MIMEType textEncodingName:(NSString )textEncodingName baseURL:(NSURL )baseURL方法
你会发现使用这个分类配合UIWebView,所有的事情都变得很简单。
- (void)loadRequest:(NSURLRequest *)request
MIMEType:(NSString *)MIMEType
textEncodingName:(NSString *)textEncodingName
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(void (^)(NSError *error))failure
// 检查参数
NSParameterAssert(request);
// 如果正处于运行或者暂停装状态,就取消之前的任务task并设置为nil
if (self.af_URLSessionTask.state == NSURLSessionTaskStateRunning || self.af_URLSessionTask.state == NSURLSessionTaskStateSuspended) {
[self.af_URLSessionTask cancel];
self.af_URLSessionTask =
__weak __typeof(self)weakSelf =
NSURLSessionDataTask *dataT
dataTask = [self.sessionManager
GET:request.URL.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id
_Nonnull responseObject) {
__strong __typeof(weakSelf) strongSelf = weakS
// 请求成功后,调用success block
if (success) {
success((NSHTTPURLResponse *)task.response, responseObject);
// 显示数据
[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[task.currentRequest URL]];
// 调用webViewDidFinishLoad
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
if (failure) {
failure(error);
self.af_URLSessionTask = dataT
// 设置progress,这个来自于self.sessionManager
if (progress != nil) {
*progress = [self.sessionManager downloadProgressForTask:dataTask];
// 开启任务
[self.af_URLSessionTask resume];
// 调用webViewDidStartLoad方法
if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
AFNetworking 的源码解读到此就结束了。我曾经说要写一个网络框架,但随着对网络的更进一步的了解。一个好的框架不是随随便便写的。需要对使用者负责。因此我又找了几个目前比较流行的框架,对他们的思想研究研究。实属拿来主义。
阅读(...) 评论()

我要回帖

更多关于 ios afnetworking 3.0 的文章

 

随机推荐