使用[NSThread sleepForTimeInterval:2.0]时,我可以停止或取消循环功能吗;在IOS中



我有一个循环函数,它名为[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

我突然想到了几个问题:

  1. 如果你的意图是取消sleepForTimeInterval,我相信你做不到。还有其他机制(如定时器)更适合这个问题。

  2. 顺便说一句,您每两秒钟发出一个异步请求。但你不能保证你之前的请求会在这段时间内完成。因此,您可能会收到多个网络请求的积压,这些请求将在视图被驳回后继续运行。

    我本以为您应该在异步请求的完成块内启动"等待两秒钟",以确保您的请求不会积压在"每两秒钟"逻辑后面。很明显,除非您使请求同步,否则这对当前的while循环不起作用,因此您可以重构此代码,用执行单个请求的东西替换while循环,在完成块中,在启动下一个请求之前等待两秒钟。

  3. 您正在检查loop的状态,等待两秒钟,然后发出请求。因此,如果视图在执行两秒睡眠时消失,那么在您完成睡眠后,没有什么可以阻止发出请求。

    至少,如果您要使用sleepForTimeInterval,您可能希望在睡眠结束后检查loop状态。但是,就我的第一点而言,最好使用一些可取消的机制,比如计时器。

  4. 如果你说你的循环永远不会退出,我建议你检查一下,确保外观方法被调用得像你认为的那样。

就我个人而言,我倾向于使用一个可以很容易地取消/无效的计时器:

  1. 定义我的属性:

    @property (nonatomic, strong) NSTimer *timer;
    @property (nonatomic, getter = isLooping) BOOL looping;
    @property (nonatomic, weak) AFHTTPRequestOperation *operation;
    
  2. 让我的外观方法设置looping变量,并根据需要启动/停止计划的请求:

    - (void)viewDidAppear:(BOOL)animated
    {
        self.looping = YES;
        [self scheduleRequestIfLooping];
    }
    - (void)viewWillDisappear:(BOOL)animated
    {
        self.looping = NO;
        [self cancelScheduledRequest];
    }
    
  3. 启动和停止调度请求的方法将使用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方法是否应该同时取消计时器和任何当前正在进行的请求(如果有的话)取决于您。

  4. 最后,将下一个请求的调度放入当前请求的完成块中。

    - (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)如果在后台线程上执行此操作,则可能需要确保对状态变量等进行了必要的线程安全处理。这对我来说似乎是一个不必要的复杂问题。

最新更新