【问题标题】:Can I stop or cancel loop function when using [NSThread sleepForTimeInterval:2.0]; in IOS使用 [NSThread sleepForTimeInterval:2.0] 时可以停止或取消循环功能吗?在IOS
【发布时间】:2013-07-12 07:56:06
【问题描述】:

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

【问题讨论】:

    标签: iphone ios objective-c nsthread nsoperation


    【解决方案1】:

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

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

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

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    

    【讨论】:

      【解决方案2】:

      我突然想到了几个问题:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-23
        • 1970-01-01
        • 2021-01-11
        • 1970-01-01
        • 1970-01-01
        • 2019-11-03
        • 2015-03-18
        • 1970-01-01
        相关资源
        最近更新 更多