4

我有一个循环函数,其中称为 [NSThread sleepForTimeInterval:2.0];。这意味着 2 秒后,循环函数被调用。我想在传递新视图时,这个循环函数停止,当返回时,再次调用它。

我使用这段代码来调用循环函数:

-(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 仍然调用。它不会停止。你有什么建议吗?

4

2 回答 2

2

您可以使用键值观察器进行尝试。您可以在以下方法中实现更改,该方法将在特定值更改时自动调用。首先,您必须为要更改的 ivar 设置通知。

[self addObserver:self forKeyPath:@"loop" options:NSKeyValueObservingOptionNew context:nil];

然后,您必须按照以下方法的要求实施更改:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
于 2014-01-23T18:04:27.207 回答
0

有几个问题突然出现在我身上:

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

于 2014-07-01T21:35:06.147 回答