+ (void)globalTimelinePostsWithBlock:(void (^)(NSArray *posts, NSError *error))block
{
[[AFAppDotNetAPIClient sharedClient] getPath:@"stream/0/posts/stream/global" parameters:nilsuccess:^(AFHTTPRequestOperation *operation, id JSON) {
NSArray *postsFromResponse = [JSON valueForKeyPath:@"data"];
NSMutableArray *mutablePosts = [NSMutableArray arrayWithCapacity:[postsFromResponse count]];
for (NSDictionary *attributes in postsFromResponse) {
Post *post = [[Post alloc] initWithAttributes:attributes];
[mutablePosts addObject:post];
}
if (block) {
block([NSArray arrayWithArray:mutablePosts], nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (block) {
block([NSArray array], error);
}
}];
}
再这个类方法中,又是通过调用AFAppDotNetAPIClient中的类方法来加载具体数据的,当具体数据加载完成之后,就直接使用传递进来的block参数直接更新UI线程中的数据。而在AFAppDotNetAPIClient中的类方法的实现如下:
- (void)getPath:(NSString *)path
parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:successfailure:failure];
[self enqueueHTTPRequestOperation:operation];
}
可以看出,最后真正请求数据的方法是AFHTTPRequestOperation,operation再初始化时会传递进success/failure两个block参数来讲完成请求之后的数据操作返回。关于enqueueHTTPRequestOperation方法实际就是讲operation加入到self.operationQueue中,然后就开始通过这个queue来管理网络请求操作行为,如果这个时候queue正在进行的operation的数量没有到达setMaxConcurrentOperationCount参数的设定,operation就会直接开始,如果到达了就会等待,总之这个时候operation合适开始合适结束的管理已经交给了queue。再来看一下queue的这个参数,是NSOperationQueueDefaultMaxConcurrentOperationCount ,也就是说这个operationqueue对所有的operation都是并发进行请求的,没有最大的请求数量的限制,operation进入queue就会开始执行。
到这里就可以发现,其实afnetwork中所有的请求都是异步的,并不支持同步请求,异步operation即支持并发的operation的实现比同步operation的实现有难度一些,而且由于里面的操作同时又都是异步的,不能直接使用自带的两种operation,只能自己去实现特定的operation,主要就是分析AFURLConnectionOperation的实现,等分析完成之后再分析AFHTTPRequestOperation以及AFHTTPClient的结构。
对AFURLConnectionOperation的分析如下:
- (id)initWithRequest:(NSURLRequest *)urlRequest {
self = [super init];
if (!self) {
return nil;
}
self.lock = [[NSRecursiveLock alloc] init]; // 用于对属性更改时的同步锁,防止出现多线程下的情况
self.lock.name = kAFNetworkingLockName; // 同步锁的名称
self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes]; // 设置runloop的mode,用于后面处理返回数据时的runloop
self.request = urlRequest; // url地址
self.outputStream = [NSOutputStream outputStreamToMemory]; // outputstream,用于将网络请求返回的数据缓冲到memory中
self.state = AFOperationReadyState; // 更改operation的state,由于重写setState方法,其中会对实现并发operation所需要实现的一些属性进行设置
return self;
}
其中需要注意的时关于setState方法的使用
- (void)setState:(AFOperationState)state {
[self.lock lock];
if (AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
NSString *newStateKey = AFKeyPathFromOperationState(state);
[self willChangeValueForKey:newStateKey];
[self willChangeValueForKey:oldStateKey];
_state = state;
[self didChangeValueForKey:oldStateKey];
[self didChangeValueForKey:newStateKey];
switch (state) {
case AFOperationExecutingState:
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
break;
case AFOperationFinishedState:
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
break;
default:
break;
}
}
[self.lock unlock];
}
这个里面尤其需要的是AFKeyPathFromOperationState,通过state获得一个string,这个string表示一些Operation中定义的KVO性质,如isReady/isExecuting/isFinished/isPaused等关键字的keypath,通过这些属性来设置operation的执行状态,我的猜想是operation通过这些KVO性质来通知operationqueue这些属性发生变化,然后在重写的- (BOOL)isReady 等方法中,通过自己定义的这些state返回不同的bool值,这样就达到了控制operation的状态的作用。比如
- (BOOL)isReady {
return self.state == AFOperationReadyState && [super isReady];
}
设置好了到readystate,接下来operationqueue会在合适的时候调用start方法,开始执行operation
- (void)start {
[self.lock lock];
if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread]withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
在start方法中,同样是通过设置setState方法来设置各种kvo的属性值来向queue通知operation状态的变化,以及通过state来确定isExcuting方法返回的bool值,这里面又用到了同步锁。这里面可以看到没有实现main方法,实现的是并发的operation,直接使用perform来在某个thread中执行operationDidstart方法,即开始执行任务,也就是非并发operation中的main做的事情。
这里面最重要的地方是通过[[self class] networkRequestThread]获取一个class共有的thread,由于使用的NSURLRequest是一个异步方法,处理数据量耗费不是很大,只用在数据返回时进行一下处理即可,所以没有必要为每一个网络请求起一个线程来运行runloop等待数据返回之后进行处理,对所有的网络请求数据返回的处理只需要一个thread即可,这个thread维护一个runloop来处理所有返回数据。
随后分析- (void)operationDidStart方法的实现,分析如何安排处理返回的网络数据