“[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]”使UI无响应
问题描述:
在UIViewController
viewDidAppear
事件中,我想从Web服务获取一些数据。而这样的代码:“[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]”使UI无响应
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSArray *arr = [self getCarList];
}
- (NSArray *)getCarList
{
if (!carList) {
ARequset *req = [[ARequset alloc] init];
[NetService sendRequest:req respClass:[Resp class] success:^(BaseResponse *response)
{
//after finished
self.requestFinished = YES;
} fail:^(NSInteger errcode, NSString *errmsg) {
self.requestFinished = YES;
}];
while (!self.requestFinished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
return carList;
}
时至运行请求成功块将不被执行,并且UI变得没有反应。
但如果我改变这样的- (void)viewDidAppear:(BOOL)animated
,一切顺利。
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelector:@selector(getCarList) withObject:self afterDelay:1];
}
答
不要做那种语法
的NetService
请求以异步方式工作的,该请求的结果在块传递 。您必须处理BaseResponse
对象并更新您的UI或任何您想要对数据执行的操作。
轮询是坏习惯,不必要地消耗系统资源。
除此之外,您正在告诉当前正在运行的UIApplication的runloop运行哪个块。
做这样的事情
- (void)getCarList
{
if (!carList) {
ARequset *req = [[ARequset alloc] init];
[NetService sendRequest:req respClass:[Resp class] success:^(BaseResponse *response)
{
//after finished
self.carList = [self doSomethingWithTheResponse:response];
dispatch_async(dispatch_get_main_queue(), ^(void) {
// Update UI
});
} fail:^(NSInteger errcode, NSString *errmsg) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
// show alert
});
}];
}
}
}
编辑:或者使用委托状的图案来处理异步行为。
取而代之的是同步方法的
- (void)methodToGetCarList
{
NSArray *cars = [self getCarList];
[self doSomethingWithCars:cars];
}
使用本
- (void)methodToGetCarListAsynchronously
{
[self getCarList];
}
和委托方法
- (void)didReceiveCars:(NSArray *)cars errorMessage:(NSString *)error
{
if (error) {
// do error handling
} else {
[self doSomethingWithCars:cars];
}
}
的getCarList
方法看起来像
- (void)getCarList
{
if (!carList) {
ARequset *req = [[ARequset alloc] init];
[NetService sendRequest:req respClass:[Resp class] success:^(BaseResponse *response)
{
//after finished
self.carList = [self doSomethingWithTheResponse:response];
[self didReceiveCars:self.carList errorMessage:nil];
} fail:^(NSInteger errcode, NSString *errmsg) {
[self didReceiveCars:nil errorMessage:errmsg];
}];
}
} else {
[self didReceiveCars:self.carList errorMessage:nil];
}
}
如果响应在后台线程中返回,代码不会考虑潜在问题。
但是,getCarList方法位于单例类中。我想用一个单例来保存cardList。是卡列表不是零,直接返回,否则请求从服务器返回。 @vadian – bohan
我编辑帖子向你展示另一种方式 – vadian
呵呵你一脸(非常感谢)@vadian – bohan