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

时间:2013-07-12 07:56:06

标签: iphone ios objective-c nsthread nsoperation

我有一个循环函数,在其中称为[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仍在调用。它不会停止。你有什么建议吗?

2 个答案:

答案 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)

有几个问题在我身上飞跃:

  1. 如果您打算真正取消sleepForTimeInterval,我绝不相信您可以这样做。还有其他机制(如计时器)更适合这个问题。

  2. 顺便说一句,您每两秒发出一次异步请求。但是,您无法保证您之前的请求将在该段时间内完成。因此,您最终可能会在视图被解除后继续运行多个网络请求的积压。

    我原本以为你想要开始等待两秒钟" 内部您的异步请求的完成块,以确保您的请求不会在您的"每两秒钟后退一步"逻辑。显然,除非您使请求同步,否则不会使用当前的while循环,因此您可能会重构此代码,将while循环替换为执行单个请求的内容,并且完成块,在开始下一个请求之前等待两秒钟。

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

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

  4. 如果您说您的循环永不退出,我建议您检查以确保外观方法被调用,就像您认为的那样。

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

    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
      }
      
    5. 在上面,我使用主线程作为计时器。如果你真的想在后台队列上做,你可以,但(a)对我来说似乎没必要,因为网络请求已经发生在后台线程上; (b)如果你在后台线程上执行此操作,您可能希望确保对状态变量等进行必要的线程安全处理。这对我来说似乎是一种不必要的复杂化。