簡體   English   中英

在計時器上退出void方法

[英]quitting a void method on a timer

我有一種與錄制視頻同時運行的方法。 當方法結束時,它將觸發其他方法的鏈,直到記錄結束為止。 我希望能夠按一個按鈕來提前停止錄制,同時也退出該方法。 我目前正在嘗試的方法是使用NSTimer來檢查是否仍在錄音,如果不是,它會停止播放音頻,還應該調用return來停止該方法。

-(void) method
{
    self.stopTimer = [NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:@selector(checkRecording) userInfo:nil repeats:YES];

    // Stuff happens
}

-(void) checkRecording
{
if (isRecording == NO)
    {
        if (player.playing == YES)
        {
            [player stop];
        }
        return;
    }

}

這將立即停止音頻,但是該方法將繼續運行直到完成。 它不會調用序列中的下一個方法,這是朝正確方向邁出的一步,但是我需要它立即停止。 我唯一的理論是,這是因為我沒有在要停止的實際方法中調用return,而是在其他方法中調用了方法,但是即使那樣,我也不確定如何解決該問題,因為就我而言知道計時器只能指向其他方法,而我不能僅僅告訴它我想要它在要停止的方法內部執行的操作。 如果這不是問題,那么我真的不確定為什么這行不通。

如果計時器有效,則可以使其無效(這將停止計時器)。

我不確定是否真的需要進行所有檢查(最后一行),但是我目前是這樣進行的:

if ( myTimer != nil && [myTimer isValid] )
{
    [myTimer invalidate];
    myTimer = nil;
}

編輯:

if ( [myTimer isValid] )
{
    [myTimer invalidate];
    myTimer = nil;
}

我唯一的理論是,因為我沒有在要停止的實際方法內調用return,而是在其他方法中調用return

你的理論是正確的。 return結束其所在的函數或方法,別無其他。 它將當前函數的上下文彈出堆棧,然后將執行返回給調用函數。

我不太確定如何解決此問題,因為據我所知,計時器只能指向其他方法,而我不能僅僅告訴它我想要它在要停止的方法內部執行的操作

我們可以使用對象存儲狀態,並使用該狀態來控制程序的流程。 該狀態可以不斷更新和檢查。 對於需要響應該狀態的更改而取消的長時間運行的任務,必須與任務並行地更新狀態。 既然您說計時器可以停止音頻,但是method中的工作沒有完成,所以我假設該method已經異步執行了長時間運行的任務。

這需要在后台執行異步長時間運行的任務(或一系列任務),並有可能取消,這與NSOperationNSOperationQueue類很好地匹配。

您可以通過實現方法或塊在NSOperation對象中執行工作。 實現您的代碼,以檢查該操作是否在所有適當的時間都已取消,並在發生這種情況時立即提供援助。

下面是一個希望與您的用例匹配的示例。 它是在iOS應用程序“空應用程序”模板中創建的,所有內容都在應用程序委托中。 我們的應用程序代表跟蹤做出是否取消決定所需的狀態,並安排一個計時器以輪詢該狀態的更改。 如果確實確定應該取消,則將工作的實際取消委托給操作隊列及其操作。

#import "AppDelegate.h"


@interface AppDelegate ()

@property (nonatomic) BOOL shouldStop; // Analogous to your isRecording variable
@property (nonatomic, strong) NSOperationQueue *operationQueue; // This manages execution of the work we encapsulate into NSOperation objects

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Typical app delegate stuff
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    // Start our long running method - analogous to method in your example
    [self method];

    return YES;
}


- (void)method
{
    // allocate operation queue and set its concurrent operation count to 1. this gives us basic ordering of
    // NSOperations. More complex ordering can be done by specifying dependencies on operations.
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    //  We create three NSBlockOperations. They only sleep the thread a little while,
    //  check if they've been cancelled and should stop, and keep doing that for a few seconds.
    //  When they are completed (either through finishing normally or through being cancelled, they
    //  log a message
    NSMutableArray *operations = [NSMutableArray array];
    for (int i = 0; i < 3; i++) {

        //  Block operations allow you to specify their work by providing a block.
        //  You can override NSOperation to provide your own custom implementation
        //  of main, or start, depending. Read the documentation for more details.
        //  The principle will be the same - check whether one should cancel at each
        //  appropriate moment and bail out if so

        NSBlockOperation *operation = [[NSBlockOperation alloc] init];

        //  For the "weak/strong dance" to avoid retain cycles
        __weak NSBlockOperation *weakOperation = operation;

        [operation addExecutionBlock:^{
            //  Weak/strong dance
            NSBlockOperation *strongOperation = weakOperation;

            //  Here is where you'd be doing actual work
            //  Either in a block or in the main / start
            //  method of your own NSOperation subclass.
            //  Instead we sleep for some time, check if
            //  cancelled, bail out if so, and then sleep some more.
            for (int i = 0; i < 300; i++) {
                if ([strongOperation isCancelled]) {
                    return;
                }
                usleep(10000);
            }
        }];

        //  The completion block is called whether the operation is cancelled or not.
        operation.completionBlock = ^{
            //  weak/strong dance again
            NSBlockOperation *strongOperation = weakOperation;
            NSLog(@"Operation completed, %@ cancelled.", [strongOperation isCancelled] ? @"WAS" : @"WAS NOT");
        };

        [operations addObject:operation];
    }

    //  Set up a timer that checks the status of whether we should stop.
    //  This timer will cancel the operations if it determines it should.
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(checkShouldKeepGoing:) userInfo:nil repeats:YES];

    //  Use GCD to simulate a stopped recording to observe how the operations react to that.
    //  Comment out to see the usual case.
    double delayInSeconds = 5;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        self.shouldStop = YES;
    });

    //  Add the operations to the operation queue, exeuction will start asynchronously from here.
    [self.operationQueue addOperations:operations waitUntilFinished:NO];
}


//  If we should stop, cancel the operations in the queue.
- (void)checkShouldKeepGoing:(NSTimer *)timer
{
    if (self.shouldStop) {
        NSLog(@"SHOULD STOP");
        [timer invalidate];
        [self.operationQueue cancelAllOperations];
    }
}

@end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM