[已解决,提供解决方案] 异步请求时block递归的问题,求帮忙看下。
需求:
从后台请求数据,一共多少条不固定。每次最多可以请求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];
}
};