AFNetwork分析

前面将NSRunloop以及NSOperation需要用到的基本知识学习理解了一下,这下终于要到我这两个月都想干的事情了,剖析一个网络framework,可惜的是asi实在过于庞大复杂了,精力不足,没有办法去渗透分析一个5000行的文件,还有对cfnetwork可能也不是很熟悉,考虑了一下,暂时还是放弃asi。先分析afnetwork,其实脑袋中现在已经有了对这个框架执行流程的大概步骤,发觉这个框架写的其实挺简单但是设计的很巧妙,再实际的页面请求数据时,可能反应没有asi那么迅速,如果在使用block的话感觉会更明显的。这个框架大量使用了gcd,所以使用起来非常方便容易上手,里面对gcd的使用也是可以借鉴的。

============================================================

再github上下载了AFNetwork的网络包,里面的使用流程我已经看了一遍,也知道是怎么回事了,但是很郁闷,不知道如何下手写文章。那就按照官方demo的执行流程来写吧。框架中有很多的网络请求类,这些请求类的积累都是AFURLConnectionOperation。下面开始写在demo中的controller请求数据的流程。

首先是使用Post对象中写了一个类方法,这个方法用来请求数据,通过block来传递数据请求返回之后的后续操作。再Post对象中实现如下:

 

+ (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 allocinitWithAttributes: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 allocinit]; // 用于对属性更改时的同步锁,防止出现多线程下的情况

    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方法的实现,分析如何安排处理返回的网络数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值