我有一个循环函数,在其中称为[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;
}
}
并且viewdisappear()
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
loop = NO;
delete=NO;
[operations cancel] ;
}
我的问题是当传递新视图时,updateArray仍在调用。它不会停止。你有什么建议吗?
答案 0 :(得分:2)
您可以使用键值观察器进行尝试。您可以使用以下方法实现更改,这些更改将自动调用为特定值更改。首先,您必须设置要更改的ivar的通知。
[self addObserver:self forKeyPath:@"loop" options:NSKeyValueObservingOptionNew context:nil];
然后,您必须按照以下方法中的要求实施更改:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
答案 1 :(得分:0)
有几个问题在我身上飞跃:
如果您打算真正取消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)如果你在后台线程上执行此操作,您可能希望确保对状态变量等进行必要的线程安全处理。这对我来说似乎是一种不必要的复杂化。