从后台请求数据,一共多少条不固定。每次最多可以请求10条(请求时传递本次请求的数据启始位置,本次请求的数据个数),每次请求会返回(数据总数,本次返回的数据启始位置,本次返回的数据个数)。我现在想请求所有数据。有什么好的解决思路吗?
每次请求10条数据,请求成功后继续请求下10条。直到请求完所有数据。
数据请求成功后通过block回调通知,所以使用了block递归。用动画写了一个模仿的代码,如下:
#import "ViewController.h"
typedef void (^myBlock)(int );
@interface ViewController ()
//测试用的视图,用闪烁此视图模仿请求。
@property (strong, nonatomic) IBOutlet UIView *testView;
@end
@implementation ViewController
//一个按钮,点击开始模仿请求
- (IBAction)blockTest:(id)sender
{
//假如请求10次
[self blockRecursion:0];
}
//模仿请求,n-请求数据开始位置
- (void)blockRecursion:(NSInteger)n
{
__weak myBlock __block block = ^(int bn)
{
NSLog(@"%d", bn);
//大于10次就退出
if(bn < 10)
{
//请求,成功后回调自己(block)
[self getData:block num:++bn];
}
};
block(0);
}
//模仿一次网络请求,成功后通过block回调
- (void)getData:(myBlock)block num:(NSInteger)bn
{
self.testView.alpha = 1;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.testView.alpha = 0;
} completion:^(BOOL finished) {
block(bn);
}];
}
@end
[self getData:block num:++bn]; 这一行有一个警告:Capturing 'block' strongly in this block is likely to lead to a retain cycle
怎么消除?(是因为Blocks 会自动 retain,所以才报retain cycle吧?加__weak?)
如果我在定义block时:myBlock __weak __block block = ^(int bn)... 警告会消失,但是getData回调时候程序会崩溃。(是因为异步请求所以block被释放了吗?)
求指点。
(http://stackoverflow.com/questions/19853878/objective-c-uiview-animate-block-recursion)
The problem with your code is that there is no strong reference to the block object. block is a weak reference. So after the statement where the block object is created, the block object can potentially be deallocated, which will set the __weak variable block to nil. Invoking a block with a nil block pointer crashes.
When you remove the __weak, you create a retain cycle -- the block retains a strong reference to itself.
What you need is two variables, one strong and one weak. The block captures the weak one. The one the block captures needs to be __block to reflect the assignment after the block was created.
myBlock blockStrong;
__block __weak myBlock blockWeak;
blockWeak = blockStrong = ^(int bn)
{
NSLog(@"%d", bn);
if(bn < 10)
{
[self getData:blockWeak num:++bn];
}
};
有点钻牛角尖了,没仔细看你的代码,感觉简单问题复杂化了。
1)是不是真的只能每次10条数据。如果数据量不大,尽可能一次取完客户端分批处理,尽量不要这样反复取,流程复杂,而且服务器请求次数多。如果数据不大,尽量先改服务端的限制。
2)假设真的数据大,那为什么又需要循环连续取完,而不是根据客户端需要的时候再取?不理解啊,这种思路很奇怪,自己找自己麻烦。
3)就算真的是数据大而且又有特殊原因要连续取完,也不该用递归那么愚蠢复杂的逻辑,你以为在做本地算法啊?!第一次请求获取总的数据条数,然后将条数除于每次最高限额的条数等于请求数,然后生成这么多个请求按顺序丢到请求队列里,如果队列是单任务的,那不需要排序,收到一条才会发下一条,顺序处理接可以。如果不确定是单任务还是并行多任务的话也很简单,每条请求里假如一个顺序号(HTTP协议里本来就有一个header可以用利用作顺序号用途,可以利用而不需要自己弄),接受到回复时按照顺序号来排列就可以了,如果数据本身就有顺序号那更简单。
总结,你的想法太混乱了,感觉是用本地逻辑来处理网络通讯。还是尽量用简单思路来解决吧。
网络通讯流程不要用递归!这不是简单与否的问题,我刚才已经说了,你是用本地逻辑去做网络通讯,不好!
我根本对你用的递归方法没兴趣,这在我看来是不能接受的最烂思路之一,所以抱歉,我不会帮你看代码细节。
我现在也用的一个开源库,刚好也是网络请求里面递归- -!不过我的比你这里简单,我哪里是下载的时候递归,局部变量递归次数过多导致栈溢出崩溃。你这个感觉也是差不多的东西了,它没完成递归,内存没释放- -!
我非常反对网络通讯采用递归设计。为什么?因为递归流程很可能过分依赖服务器的回复,但是网络通讯最根本一条原则就是你不能信任网络传输的可靠性,也许网络断了,也许服务器的数据不完整或者出错,这样就有可能造成递归里出现莫名其妙的问题。所以最好的方法还是保险,一切发起请求的处理是在客户端完全可控的前提下进行的,但递归有很多边界条件需要考虑,不完全可控。
至于retain cycle,还是自己看吧,弄明白你会增进不少,学东西就是得一边猜一边摸索。不过关键是其实我还没大量使用ARC,所以不好回答,呵呵。