iOS开发-AFNetworking/NSURLSession异步处理

相信对于GitHub上著名的AFNetworking API,一定都不陌生。本文是一篇基础使用的心得,老手请绕行。

AFNetworking与NSURLSession都是依靠block内的代码进行异步处理来得到网络数据(比如by jSON格式),这样做的好处就是不会阻塞主队列的进程,当block内的代码执行完毕时,进行回调处理,回到主队列。这样当需要得到很多网络数据时,不会让用户在一个空白的页面等待很久,可以把不需要网络数据的部分提前加载,增加用户体验。而且现在NSURLConnection这种在主队列操作的方法已经deprecated了,尽量使用这两种异步处理的方式。

以下为AFNetworking的示例代码(使用jSON格式,源为iTunes RSS top 10 songs)

 1 #import "FetchData.h"
 2 #import <AFNetworking/AFNetworking.h>
 3 
 4 @implementation FetchData
 5 
 6 - (void)fetchData
 7 {
 8     self.resultArray = [[NSMutableArray alloc]init];
 9     AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc]init];
10     [manager GET:@"https://itunes.apple.com/us/rss/topsongs/limit=10/json" parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, NSDictionary *responseObject) {
11         NSDictionary *feed = [responseObject objectForKey:@"feed"];
12         NSArray *entry = [feed objectForKey:@"entry"];
13         for (NSDictionary *detailDict in entry) {
14             [self.resultArray addObject:[detailDict valueForKeyPath:@"title.label"]];
15         }
16         [[NSNotificationCenter defaultCenter]postNotificationName:@"reload" object:self];
17         
18         
19     } failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
20         NSLog(@"%@", [error description]);
21     }];
22 }

关于import AFNetworking API ,链接https://github.com/AFNetworking/AFNetworking

 1 - (void)fetchSessionData
 2 {
 3     self.resultArray = [[NSMutableArray alloc]init];
 4     NSURLSession *session = [NSURLSession sharedSession];
 5     NSURL *url = [NSURL URLWithString:@"https://itunes.apple.com/us/rss/topsongs/limit=10/json"];
 6     NSURLRequest *request = [NSURLRequest requestWithURL:url];
 7     NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
 8         NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
 9         NSDictionary *feed = [json objectForKey:@"feed"];
10         NSArray *entry = [feed objectForKey:@"entry"];
11         for (NSDictionary *detailDict in entry) {
12             [self.resultArray addObject:[detailDict valueForKeyPath:@"title.label"]];
13             
14         }
15         [[NSNotificationCenter defaultCenter]postNotificationName:@"reload" object:self];
16     }];
17     [dataTask resume];
18 }

 

[[NSNotificationCenter defaultCenter]postNotificationName:@"reload" object:self];

是关键,因为是异步处理,所以并不知道block内的内容会什么时候完成,由于示例在MVC结构下,所以使用[NSNotificationCenter]来监控block执行情况,如果方法都在一个ViewController中,则将该代码换成[self.tableView reloadData];

这里说明一下原因,因为UIKit控件都是依据所在的viewController存在的,即使属性改为strong,依然会在此viewcontroller消失后也会release,所以如果是MVC结构,在Model文件中,即使初始化了一个viewController的实例,并使其tableView reloadData,重新返回这个viewController时,还是会再初始化这个tableView所以是无效的。

之后是viewController代码

 1 @interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
 2 @property (nonatomic)UITableView *tableView;
 3 @property (nonatomic)FetchData *fetchData;
 4 @end
 5 
 6 @implementation ViewController
 7 
 8 - (void)viewDidLoad {
 9     [super viewDidLoad];
10     self.tableView = [[UITableView alloc]initWithFrame:self.view.bounds];
11     [self.tableView setDelegate:self];
12     [self.tableView setDataSource:self];
13     [self.view addSubview:self.tableView];
14     self.fetchData = [[FetchData alloc]init];
15     [self.fetchData fetchData];
16     
17     [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(reload) name:@"reload" object:nil];
18 }
19 
20 - (void)reload{
21     [self.tableView reloadData];
22     [[NSNotificationCenter defaultCenter]removeObserver:self name:@"reload" object:nil];
23 }
24 
25 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
26 {
27     return 1;
28 }
29 
30 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
31 {
32     return self.fetchData.resultArray.count;
33 }
34 
35 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
36 {
37     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
38     if (!cell) {
39         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
40     }
41     cell.textLabel.text = [self.fetchData.resultArray objectAtIndex:indexPath.row];
42     return cell;
43 }

注意17行,以及20行的reload方法,在调用fetchData方法之后,发出一个观察者,当观察到post出的notification时,则调用reload方法,刷新tableView,实现异步处理

以下是一个NSURLSession版在viewController里实现的方法,与AFNetworking大同小异

 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     self.tableView = [[UITableView alloc]initWithFrame:self.view.bounds];
 4     [self.tableView setDelegate:self];
 5     [self.tableView setDataSource:self];
 6     [self.view addSubview:self.tableView];
 7     [self fetchSessionData];
 8 }
 9 
10 - (void)fetchSessionData
11 {
12     self.resultArrayLocal = [[NSMutableArray alloc]init];
13     NSURLSession *session = [NSURLSession sharedSession];
14     NSURL *url = [NSURL URLWithString:@"https://itunes.apple.com/us/rss/topsongs/limit=10/json"];
15     NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
16         NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
17         NSDictionary *feed = [json objectForKey:@"feed"];
18         NSArray *entry = [feed objectForKey:@"entry"];
19         for (NSDictionary *detailDict in entry) {
20             //[self.resultArrayLocal addObject:[detailDict valueForKeyPath:@"title.label"]];
21             NSDictionary *title = [detailDict objectForKey:@"title"];
22             NSString *str = [title objectForKey:@"label"];
23             [self.resultArrayLocal addObject:str];
24             
25         }
26         
27         [self.tableView reloadData];
28     }];
29     [dataTask resume];
30 }
31 
32 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
33 {
34     return 1;
35 }
36 
37 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
38 {
39     return self.fetchData.resultArray.count;
40 }
41 
42 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
43 {
44     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
45     if (!cell) {
46         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
47     }
48     cell.textLabel.text = [self.fetchData.resultArray objectAtIndex:indexPath.row];
49     return cell;
50 }

主要是想提一下MVC下[NSNotificationCenter]的用法,由此,异步刷新实现

欢迎光临我的主页:http://www.jiachengzhi.com

 

posted @ 2015-10-27 00:45  ChrisUpForever  Views(1456)  Comments(0Edit  收藏  举报