我有一个与录制视频同时运行的方法。当方法结束时,它会触发一系列其他方法,直到录制结束。我希望能够按下按钮以提前停止录制,同时也退出该方法。我目前正在尝试这样做的方法是使用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;
}
}
这会立即停止音频但方法会继续运行直到完成。它不会调用序列中的下一个方法,这是朝着正确方向迈出的一步,但我需要它立即停止。我唯一的理论是,因为我没有在我想要停止的实际方法中调用返回,而是在另一种方法中,但即使是这样,我也不确定如何解决这个问题,因为就我而言知道计时器只能指向其他方法,我不能只告诉它我希望它在我想要停止的方法中做什么。如果这不是问题那么我真的不确定为什么这不起作用。
答案 0 :(得分:0)
如果计时器有效,您可以使计时器无效(停止计时器)。
我不确定是否所有检查都是必要的(&最后一行),但我现在这样做:
if ( myTimer != nil && [myTimer isValid] )
{
[myTimer invalidate];
myTimer = nil;
}
编辑:
if ( [myTimer isValid] )
{
[myTimer invalidate];
myTimer = nil;
}
答案 1 :(得分:0)
我唯一的理论是因为我没有在我想要停止的实际方法中调用return而是在另一种方法中调用
你的理论是正确的。 return
结束它所在的函数或方法,而不是其他任何东西。它将当前函数的上下文弹出堆栈并将执行返回给调用函数。
我不确定如何解决这个问题,因为据我所知,计时器只能指向其他方法而我无法告诉它我希望它在我的方法中做什么想要停止
我们可以使用对象来存储状态并使用该状态来控制程序的流程。可以不断更新和检查该状态。对于需要取消以响应该状态更改的长时间运行的任务,必须与该任务并行更新状态。既然你说定时器可以用来停止音频,但method
中完成的工作没有,我假设method
已经异步执行其长时间运行的任务。< / p>
这需要在后台执行异步长时间运行的任务(或一系列任务),可以取消,与NSOperation
和NSOperationQueue
类很好地匹配。
您可以通过实现方法或块在NSOperation
个对象中执行您的工作。实施您的代码以检查操作是否在所有适当的时间被取消,并在发生这种情况时立即挽救。
以下是一个有希望与您的用例匹配的示例。它是在iOS应用程序中创建的空应用程序&#39;模板一切都在应用程序委托中。我们的应用程序代表会跟踪决定是否取消的状态,还会安排计时器轮询该状态的更改。如果它确定它应该取消,它会将实际的工作取消委托给操作队列及其操作。
#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