我有一个循环函数,它名为[NSThread sleepForTimeInterval:2.0];。这意味着在2s之后,调用循环函数。我想当传递新视图时,这个循环函数会停止,当返回时,它会被再次调用。
我用这个代码调用循环函数:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
loop = YES;
delete=NO;
temp = [FileCompletedArray mutableCopy];
NSOperationQueue *queue = [NSOperationQueue new];
operations = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(updateArray) object:nil];
[queue addOperation:operations];
[operations release];
}
和循环功能:
-(void)updateArray{
while (loop)
{
NSLog(@"start loop");
if(loop){
[NSThread sleepForTimeInterval:2.0];
NSLog(@"start send request");
NSURL *url1 = [NSURL URLWithString:@"http://server.com"];
NSMutableURLRequest *afRequest = [httpClient requestWithMethod:@"POST" path:nil parameters:params1] ;
operation= [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
NSLog(@" request sent");
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Server response1");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"error: %@", error);
}
];
[httpClient enqueueHTTPRequestOperation:operation];
}
else
return;
}
}
和视图消失()
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
loop = NO;
delete=NO;
[operations cancel] ;
}
我的问题是,当传递新视图时,updateArray仍然调用。它没有停止。你有什么建议吗?
您可以使用键值观测器进行尝试。您可以在以下方法中实现更改,该方法将在特定值更改时自动调用。首先,您必须为将要更改的ivar设置通知。
[self addObserver:self forKeyPath:@"loop" options:NSKeyValueObservingOptionNew context:nil];
然后,您必须按照以下方法中的要求实施更改:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
我突然想到了几个问题:
-
如果你的意图是取消
sleepForTimeInterval
,我相信你做不到。还有其他机制(如定时器)更适合这个问题。 -
顺便说一句,您每两秒钟发出一个异步请求。但你不能保证你之前的请求会在这段时间内完成。因此,您可能会收到多个网络请求的积压,这些请求将在视图被驳回后继续运行。
我本以为您应该在异步请求的完成块内启动"等待两秒钟",以确保您的请求不会积压在"每两秒钟"逻辑后面。很明显,除非您使请求同步,否则这对当前的
while
循环不起作用,因此您可以重构此代码,用执行单个请求的东西替换while
循环,在完成块中,在启动下一个请求之前等待两秒钟。 -
您正在检查
loop
的状态,等待两秒钟,然后发出请求。因此,如果视图在执行两秒睡眠时消失,那么在您完成睡眠后,没有什么可以阻止发出请求。至少,如果您要使用
sleepForTimeInterval
,您可能希望在睡眠结束后检查loop
状态。但是,就我的第一点而言,最好使用一些可取消的机制,比如计时器。 -
如果你说你的循环永远不会退出,我建议你检查一下,确保外观方法被调用得像你认为的那样。
就我个人而言,我倾向于使用一个可以很容易地取消/无效的计时器:
-
定义我的属性:
@property (nonatomic, strong) NSTimer *timer; @property (nonatomic, getter = isLooping) BOOL looping; @property (nonatomic, weak) AFHTTPRequestOperation *operation;
-
让我的外观方法设置
looping
变量,并根据需要启动/停止计划的请求:- (void)viewDidAppear:(BOOL)animated { self.looping = YES; [self scheduleRequestIfLooping]; } - (void)viewWillDisappear:(BOOL)animated { self.looping = NO; [self cancelScheduledRequest]; }
-
启动和停止调度请求的方法将使用
NSTimer
:- (void)scheduleRequestIfLooping { if ([self isLooping]) { self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(initiateRequest:) userInfo:nil repeats:NO]; } } - (void)cancelScheduledRequest { [self.timer invalidate]; self.timer = nil; // you might want to cancel any `AFHTTPRequestOperation` // currently in progress, too [self.operation cancel]; }
请注意,
cancel
方法是否应该同时取消计时器和任何当前正在进行的请求(如果有的话)取决于您。 -
最后,将下一个请求的调度放入当前请求的完成块中。
- (void)initiateRequest:(NSTimer *)timer { // create AFHTTPRequestOperation AFHTTPRequestOperation operation = ... // now schedule next request _after_ this one, by initiating that request in the completion block [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Server response1"); [self scheduleRequestIfLooping]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"error: %@", error); // not sure if you want to schedule request if last one failed }]; self.operation = operation; // save this in the property }
在上面的文章中,我使用了定时器的主线程。如果你真的想在后台队列上完成,你可以,但(a)对我来说似乎没有必要,因为网络请求已经发生在后台线程上;(b)如果在后台线程上执行此操作,则可能需要确保对状态变量等进行了必要的线程安全处理。这对我来说似乎是一个不必要的复杂问题。