2008-12-07 39 views
41

Tôi đang sử dụng NSTimer để thực hiện một số hiển thị trong ứng dụng iPhone dựa trên OpenGL. Tôi có một hộp thoại phương thức bật lên và yêu cầu đầu vào của người dùng. Trong khi người dùng được cung cấp đầu vào, tôi muốn "tạm dừng" nghĩa là một cái gì đó như thế này:Tôi có thể tạm dừng một NSTimer theo cách lập trình bằng cách nào?

[myNSTimer pause]; 

Tôi đang sử dụng cú pháp này bởi vì tôi đã làm những việc như:

[myNSTimer invalidate]; 

khi tôi muốn nó dừng lại.

Tôi có thể tạm dừng chương trình NSTimer bằng cách nào?

+9

@fishcharlie link bị hỏng – Till

Trả lời

20

Từ đây:

http://discussions.apple.com/thread.jspa?threadID=1811475&tstart=75

"Bạn có thể lưu trữ số lượng thời gian đã trôi qua kể từ bộ đếm thời gian bắt đầu ... Khi bộ đếm thời gian bắt đầu lưu trữ ngày trong một biến NSDate Sau đó, khi người sử dụng. switch ... sử dụng phương thức timeIntervalSinceNow trong lớp NSDate để lưu lượng thời gian đã trôi qua ... lưu ý rằng điều này sẽ cho giá trị âm cho timeIntervalSinceNow Khi người dùng trả về giá trị đó để thiết lập một bộ đếm thời gian thích hợp. Tôi không nghĩ rằng có một cách để tạm dừng và khởi động lại một bộ đếm thời gian. uation. "

+3

Cảm ơn bạn đã trả lời. Có lẽ nó có thể được giải quyết bằng cách loại bỏ bộ đếm thời gian đầu tiên ... sau đó tạo một bộ đếm thời gian hoàn toàn mới sau khi người dùng cung cấp đầu vào. – MrDatabase

+1

Để tạm dừng bộ hẹn giờ, hãy gửi tin nhắn 'không hợp lệ' tới bộ hẹn giờ của bạn và đặt nó thành không sau đó. Để tiếp tục hẹn giờ, hãy đặt nó thành [NSTimer schedul .....]. Về cơ bản, loại bỏ cái cũ của bạn và sau đó tạo một cái mới với cùng một thuộc tính. Những gì tôi tìm thấy cách dễ nhất :) –

+1

Đó là không giống nhau mặc dù. Nếu bạn tạm dừng bộ hẹn giờ, nó sẽ có một khoảng thời gian còn lại trước sự kiện hẹn giờ tiếp theo. Nếu bạn loại bỏ nó và bắt đầu một cái mới, nó sẽ luôn luôn có số lượng thời gian ban đầu trước khi một sự kiện, đó là sai. –

8

Trong trường hợp của tôi, tôi đã có một biến 'giây', và một 'timerIsEnabled'. Khi tôi muốn tạm dừng bộ đếm thời gian, chỉ cần thực hiện timerIsEnabled là sai. Vì biến giây chỉ tăng lên nếu timerIsEnabled là true, tôi cố định vấn đề của tôi Hope this helps

10

Con đường tôi thực hiện điều này là bằng cách lưu trữ ngày bắn của NSTimer trong một biến và sau đó thiết lập ngày bắn để INFINITY

Khi tôi tạm dừng:...

pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain]; 
previousFiringDate = [timer firingDate]; 
[timer setFiringDate:INFINITY] 

Khi tôi bỏ tạm dừng, tôi thêm amou nt thời gian mà bộ đếm thời gian đã dừng lại để ngày bắn trước:

float pauseTime = -1*[pauseStart timeIntervalSinceNow]; 
[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]]; 

này làm cho nó dễ dàng hơn rất nhiều so với lo lắng về việc hủy bỏ hiệu lực và reinitializing bộ đếm thời gian. Tôi đã có rất nhiều bộ hẹn giờ vì vậy tôi chỉ cần đặt tất cả trong một mảng và đã làm điều này cho tất cả chúng. Tôi đã phân lớp NSTimer để giữ cho previousFiringDate được kết hợp với bộ đếm thời gian đó.

Điều này cũng tốt hơn việc sử dụng BOOL cho dù có bị tạm dừng hay không vì vậy các hành động sẽ không diễn ra nếu BOOL được đặt. Điều này là bởi vì nếu một cái gì đó sắp xảy ra trước khi bạn tạm dừng, nó sẽ không xảy ra sau khi bạn bỏ nó vì nó sẽ bị bỏ qua.

+1

Điều đó có thể hoạt động, nhưng theo [tài liệu tham khảo] (http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html): 'Subclassing Ghi chú Bạn không nên cố gắng phân lớp NSTimer.' – Jon

7

Cách đơn giản nhất tôi quản lý để làm điều đó là như thế này:

-(void) timerToggle{ 
    if (theTimer == nil) { 
     float theInterval = 1.0/30.0; 
     theTimer = [NSTimer scheduledTimerWithTimeInterval:theInterval target:self selector:@selector(animateBall:) userInfo:nil repeats:YES]; 
    } else { 
     [theTimer invalidate]; 
     theTimer = nil; 
    } 
} 
+0

Ký hiệu 1.0/30.0 có nghĩa là gì? – zakdances

+0

@yourfriendzak: Đó là tốc độ bắn/khoảng thời gian mà bộ chọn giờ được gọi. Trong trường hợp này, 1/30 là mỗi 0,03 giây. – Luke

35

Chỉ cần nghĩ đến việc cập nhật các bản sửa lỗi nhỏ để kapesoftware 's câu trả lời:

NSDate *pauseStart, *previousFireDate; 

-(void) pauseTimer:(NSTimer *)timer { 

    pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain]; 

    previousFireDate = [[timer fireDate] retain]; 

    [timer setFireDate:[NSDate distantFuture]]; 
} 

-(void) resumeTimer:(NSTimer *)timer { 

    float pauseTime = -1*[pauseStart timeIntervalSinceNow]; 

    [timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]]; 

    [pauseStart release]; 

    [previousFireDate release]; 
} 
+0

điều này hoạt động tốt nhưng khi tôi tạm dừng nó ..its tạm dừng chúng thời gian và khi tôi tiếp tục nó ... nó bắt đầu với thời gian hiện tại – Christien

+3

Thay vì '[NSDate dateWithTimeIntervalSinceNow: 0]' bạn chỉ có thể làm '[NSDate date]' . – DarkDust

0

Bạn không thể tạm dừng NSTimer như đã đề cập ở trên. Vì vậy, thời gian để bị bắt không nên phụ thuộc vào Timer bắn, tôi đề nghị.Đây là giải pháp đơn giản nhất của tôi:

Khi tạo bộ đếm thời gian khởi tạo đơn vị thời gian bắt đầu như:

self.startDate=[NSDate date]; 
self.timeElapsedInterval=[[NSDate date] timeIntervalSinceDate:self.startDate];//This ``will be 0 //second at the start of the timer.``  

myTimer= [NSTimer scheduledTimerWithTimeInterval:1.0 target:self `selector:@selector(updateTimer) userInfo:nil repeats:YES]; 

' Bây giờ trong bản cập nhật timer phương pháp:

NSTimeInterval unitTime=1; 
-(void) updateTimer 
{ 
if(self.timerPaused) 
     { 
      //Do nothing as timer is paused 
     } 
else{ 
    self.timerElapsedInterval=timerElapsedInterval+unitInterval; 
    //Then do your thing update the visual timer texfield or something. 
    } 

} 
2

Cũ câu hỏi, nhưng tôi chỉ đã viết một lớp tiện ích hạng nhẹ để thực hiện chính xác những gì OP đang tìm kiếm.

https://github.com/codeslaw/CSPausibleTimer

Hỗ trợ bộ hẹn giờ lặp lại. Hy vọng nó có ích!

+0

Điều này có vẻ tuyệt vời. Tôi đang kiểm tra nó ra ngay bây giờ. Cảm ơn! –

+0

Mã của bạn cho biết "Bản quyền 2013" và "Tất cả các quyền được bảo lưu". bạn có phiền không nếu tôi sử dụng nó trong một dự án có khả năng sinh lợi? –

+0

@thunder rabbit - vâng, làm ơn. Tôi chắc chắn sẽ thay đổi văn bản giấy phép khi tôi có cơ hội. Bạn được tự do sử dụng nó tuy nhiên bạn muốn – Chris

5

Đây là danh mục trên NSTimer cho phép chức năng tạm dừng và tiếp tục.

Tiêu đề:

#import <Foundation/Foundation.h> 

@interface NSTimer (CVPausable) 

- (void)pauseOrResume; 
- (BOOL)isPaused; 

@end 

Thực hiện:

#import "NSTimer+CVPausable.h" 
#import <objc/runtime.h> 

@interface NSTimer (CVPausablePrivate) 

@property (nonatomic) NSNumber *timeDeltaNumber; 

@end 

@implementation NSTimer (CVPausablePrivate) 

static void *AssociationKey; 

- (NSNumber *)timeDeltaNumber 
{ 
    return objc_getAssociatedObject(self, AssociationKey); 
} 

- (void)setTimeDeltaNumber:(NSNumber *)timeDeltaNumber 
{ 
    objc_setAssociatedObject(self, AssociationKey, timeDeltaNumber, OBJC_ASSOCIATION_RETAIN); 
} 

@end 


@implementation NSTimer (CVPausable) 

- (void)pauseOrResume 
{ 
    if ([self isPaused]) { 
     self.fireDate = [[NSDate date] dateByAddingTimeInterval:[self.timeDeltaNumber doubleValue]]; 
     self.timeDeltaNumber = nil; 
    } 
    else { 
     NSTimeInterval interval = [[self fireDate] timeIntervalSinceNow]; 
     self.timeDeltaNumber = @(interval); 
     self.fireDate = [NSDate distantFuture]; 
    } 
} 

- (BOOL)isPaused 
{ 
    return (self.timeDeltaNumber != nil); 
} 

@end 
+0

Tôi thích câu trả lời danh mục! Cuốn sách đó đâu rồi! – rezwits

0

Vâng, tôi tìm thấy điều này như là phương pháp tốt nhất để thực hiện tạm dừng một bộ đếm thời gian điều. Sử dụng biến tĩnh để chuyển đổi tạm dừng và tiếp tục. Trong tạm dừng, vô hiệu hóa bộ đếm thời gian và đặt nó thành không và trong phần tiếp tục đặt lại bộ hẹn giờ bằng cách sử dụng mã ban đầu mà nó được bắt đầu.

Mã sau đây hoạt động trên phản hồi đối với nút nhấp tạm dừng.

-(IBAction)Pause:(id)sender 
{ 
    static BOOL *PauseToggle; 
    if(!PauseToggle) 
    { 
     [timer invalidate]; 
     timer = nil; 
     PauseToggle = (BOOL *) YES; 
    } 
    else 
    { 
     timer = [NSTimer scheduledTimerWithTimeInterval:0.04 target:self selector:@selector(HeliMove) userInfo:nil repeats:YES]; 
     PauseToggle = (BOOL *) NO; 
    } 
} 
+0

Điều này sẽ không hoạt động nếu khoảng thời gian đủ dài để được chú ý. Nếu khoảng thời gian của bạn sẽ là 10 giây và bạn sẽ tạm dừng bộ hẹn giờ sau 5 giây, bộ hẹn giờ sẽ còn 5 giây khi bạn bật lại tính năng này. Giải pháp của bạn sẽ bắt đầu hẹn giờ từ 10 giây khi bật lại. –

+0

Tôi đang sử dụng bộ hẹn giờ để thực hiện tác vụ lặp lại không tính thời gian. Vì vậy, trường hợp của tôi sẽ được giải quyết. – divyenduz

-1

Tôi cũng cần NSTimer tạm dừng. Sau khi đọc chủ đề này và các câu trả lời của bạn và nhận ra rằng điều duy nhất tôi cần là đặt fireDate của timer thành tương lai xa và sau đó quay lại Hiện tôi đã tạo danh mục cho NSTimer bằng các phương thức Tạm dừng và Tiếp tục. Vì vậy, tôi chỉ có thể tạm dừng hẹn giờ bằng cách gọi [myTimer pause]; và tiếp tục bằng cách gọi [myTimer resume]; phương pháp. Ở đây nó là, hy vọng rằng nó sẽ giúp một ai đó.

Interface:

#import <Foundation/Foundation.h> 

@interface NSTimer (Pausable) 

-(void)pause; 
-(void)resume; 

@end 

Thực hiện:

#import "NSTimer+Pausable.h" 

@implementation NSTimer (Pausable) 

-(void)pause 
{ 
    [self setFireDate:[NSDate dateWithTimeIntervalSinceNow:[NSDate distantFuture]]]; //set fireDate to far future 
} 

-(void)resume 
{ 
    [self setFireDate:[NSDate date]]; 
} 

@end 
+0

Bạn nên sử dụng [NSDate distantFuture] thay vì 31.536.000 – odyth

+0

Vâng, điểm tốt, nhờ – jano

+0

'dateWithTimeIntervalSinceNow: 'mất một' NSTimeInterval', thay vì gửi nó' [[NSDate distantFuture] timeoutInterval] ' –

2

Dựa tắt @Thiru và @ kapesoftware của câu trả lời, tôi đã tạo một danh mục Mục tiêu-C trên NSTimer sử dụng đối tượng liên kết để tạm dừng và tiếp tục hẹn giờ.

#import <objc/runtime.h> 

@interface NSTimer (PausableTimer) 

@property (nonatomic, retain) NSDate *pausedDate; 

@property (nonatomic, retain) NSDate *nextFireDate; 

-(void)pause; 

-(void)resume; 

@end 

...

@implementation NSTimer (PausableTimer) 

static char * kPausedDate = "pausedDate"; 
static char * kNextFireDate = "nextFireDate"; 

@dynamic pausedDate; 
@dynamic nextFireDate; 

-(void)pause { 

    self.pausedDate = [NSDate date]; 

    self.nextFireDate = [self fireDate]; 

    [self setFireDate:[NSDate distantFuture]]; 
} 

-(void)resume 
{ 
    float pauseTime = -1*[self.pausedDate timeIntervalSinceNow]; 

    [self setFireDate:[self.nextFireDate initWithTimeInterval:pauseTime sinceDate:self.nextFireDate]]; 
} 

- (void)setPausedDate:(NSDate *)pausedDate 
{ 
    objc_setAssociatedObject(self, kPausedDate, pausedDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

- (NSDate *)pausedDate 
{ 
    return objc_getAssociatedObject(self, kPausedDate); 
} 

- (void)setNextFireDate:(NSDate *)nextFireDate 
{ 
    objc_setAssociatedObject(self, kNextFireDate, nextFireDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

- (NSDate *)nextFireDate 
{ 
    return objc_getAssociatedObject(self, kNextFireDate); 
} 

Nó giữ mọi thứ gọn gàng và có nghĩa là bạn không cần phải tạo ra các biến dụ hoặc tài sản chỉ để tạm dừng và tiếp tục tính giờ của bạn.

+0

Đã đẩy dự án Xcode tới Github https://github.com/tobygundry/PausableTimer, bao gồm bảng phân cảnh cơ bản để thử nghiệm. – Toby

0

Mã bên dưới là để sử dụng với chế độ xem cuộn, mang lại nội dung vào khoảng thời gian đều đặn và lặp lại trước khi hoàn thành, nhưng cùng một logic có thể được sử dụng cho bất kỳ nút tạm dừng/khởi động lại nào.

Bộ hẹn giờ kích hoạt khi tải (initiateFeatureTimer) và tạm dừng cho tương tác người dùng (sẽ bắt đầu phương pháp kéo), cho phép người dùng xem nội dung miễn là cô ấy thích. Khi người dùng nhấc ngón tay của mình lên (sẽ kết thúc kéo), đối tượng featurePaused boolean được đặt lại, nhưng bạn cũng có tùy chọn thêm vào một chút chậm trễ hơn.

Bằng cách này, thiết bị cuộn không di chuyển ngay lập tức khi nhấc ngón tay, nó phản ứng nhanh hơn với người dùng.

//set vars, fire first method on load. 
featureDelay = 8; //int 
featureInt = featureDelay-1; //int 
featurePaused = false; //boolean 

-(void)initiateFeatureTimer { 
    featureTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(moveFeatureScroller) userInfo:nil repeats:true]; 
    [featureTimer fire]; 
} 
-(void)moveFeatureScroller { 

    if (!featurePaused){ //check boolean 
     featureInt++; 

     if (featureInt == featureDelay){ 
      featureInt = 0; //reset the feature int 

      /*//scroll logic 
      int nextPage = (featurePage + 1) * w; 
      if (featurePage == features.count-1){ nextPage = 0; } 
      [featureScroller setContentOffset:CGPointMake(nextPage, 0)]; */   
     } 
     } 
} 

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { 
    featurePaused = true; //pause the timer 
} 
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { 
    featurePaused = false; //restart the timer 
    featureInt = -3; //if you want to add an additional delay 
} 
0

Nếu khoảng thời gian lửa của bạn là khoan dung, bạn có thể sử dụng CADisplayLink thay vì NSTimer. Bởi vì CADisplayLink hỗ trợ -pause.

displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(fireMethod:)]; 
displayLink.frameInterval = approximateVaue;//CADisplayLink's frame rate is 60 fps. 
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

//pause 
[displayLink pause]; 
Các vấn đề liên quan