2013-02-17 26 views
38

Tôi muốn có thể lên lịch cho ba sự kiện nhỏ trong tương lai mà không phải viết một hàm cho mỗi sự kiện. Làm thế nào tôi có thể làm điều này bằng cách sử dụng NSTimer? Tôi hiểu các khối tạo điều kiện thuận lợi cho các chức năng ẩn danh nhưng chúng có thể được sử dụng trong phạm vi NSTimer và nếu có, làm thế nào?NSTimer với chức năng/khối ẩn danh?

[NSTimer scheduledTimerWithTimeInterval:gameInterval 
     target:self selector:@selector(/* I simply want to update a label here */) 
     userInfo:nil repeats:NO]; 
+3

Tại sao bạn không sử dụng 'dispatch_after()'? Đó là một hàm GCD và lấy một khối làm tham số. –

+0

Không bao giờ nghe nói về nó ... Làm thế nào để sử dụng?Miễn là tôi có thể nói "chờ đợi X giây sau đó làm điều này" Tôi hạnh phúc! – Chris

+1

Còn phương thức '–performSelector: withObject: afterDelay:' thì sao? – holex

Trả lời

22

Bạn thực sự có thể gọi:

NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval, 
 
        target: AnyObject, 
 
        selector: #Selector, 
 
        userInfo: AnyObject?, 
 
        repeats: Bool)

Sử dụng nó như thế này:

NSTimer.scheduledTimerWithTimeInterval(1, 
 
        target: NSBlockOperation(block: {...}), 
 
        selector: #selector(NSOperation.main), 
 
        userInfo: nil, 
 
        repeats: true)

+0

Thật tuyệt vời. Cảm ơn. –

+0

Nhanh chóng và đơn giản. Hoạt động tuyệt vời. Cảm ơn! – Vitalii

+0

Đây phải là câu trả lời được chọn vì nó cho phép vô hiệu hóa bộ đếm thời gian mà câu trả lời được chấp nhận thì không. –

56

Bạn có thể sử dụng dispatch_after nếu bạn muốn đạt được điều gì đó tương tự như NSTimer và thực thi khối.

Đây là đoạn mã mẫu cho cùng:

int64_t delayInSeconds = gameInterval; // Your Game Interval as mentioned above by you 

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 

     // Update your label here. 

    }); 

Hope this helps.

+9

Lưu ý! Bạn đã sử dụng một int64_t cho sự chậm trễ của bạn trong vài giây, do đó, điều này sẽ chỉ làm việc cho toàn bộ số giây! GameInterval, tôi đoán là chưa đầy 1 giây, vì vậy điều này sẽ không làm những gì bạn muốn. (Mẫu Xcode cho điều này là khá lừa đảo.) –

+1

Jesse là đúng. Lưu ý rằng tham số thực tế chấp nhận giá trị được đo bằng * nano giây * mặc dù, do đó hằng số 'NSEC_PER_SEC'. Vì vậy, bạn chắc chắn có thể chỉ định phân số của một giây, nhưng bạn phải cẩn thận với các loại số của bạn. Một cái gì đó như '(int64_t) (gameInterval * (double) NSEC_PER_SEC)' trong đó 'gameInterval' là một' double' sẽ hoạt động. – devios1

+1

Bài đăng hỏi cách thực hiện việc này với NSTimer. Tôi không thể vô hiệu hóa bằng dispatch_after. – circuitry

6

Nó khá dễ dàng, nhưng nó không được bao gồm trong khung Apple, chưa được ít nhất.

Bạn có thể tự viết một trình bao bọc khối cho chính mình NSTimer, ví dụ: sử dụng GCD hoặc bạn có thể sử dụng các thư viện của bên thứ ba hiện có như thư viện này: https://github.com/jivadevoe/NSTimer-Blocks.

7

Objective-C phiên bản của câu trả lời @ Peter Peng của:

_actionDelayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[NSBlockOperation blockOperationWithBlock:^{ 
    NSLog(@"Well this is useless."); 
}] selector:@selector(main) userInfo:nil repeats:YES]; 
9

A block based timer API exists in Cocoa (như iOS 10+/MacOS 10.12+) - đây là cách bạn có thể sử dụng nó trong Swift 3:

Timer(timeInterval: gameInterval, repeats: false) { _ in 
    print("herp derp") 
} 

... hoặc trong Objective-C:

[NSTimer scheduledTimerWithTimeInterval:gameInterval repeats:NO block:^(NSTimer *timer) { 
    NSLog(@"herp derp"); 
}]; 

Nếu bạn cần nhắm mục tiêu các phiên bản hệ điều hành cũ hơn iOS10, macOS 12, tvOS 10, watchOS 3, bạn nên sử dụng một trong các giải pháp khác.

+1

Tôi rất vui khi khám phá thêm tính năng này gần đây. Do chúng tôi đã có các khối kể từ iOS 4, thật ngạc nhiên khi Apple mất cho đến iOS 10 để ném vào một API dựa trên khối cho NSTimer! –

+1

Đáng ngạc nhiên điều này không hiệu quả đối với tôi, ít nhất là không có trong Objective-C. Khối đơn giản không bao giờ được gọi. Nó không phải là một vấn đề với thời gian chờ vì khởi tạo NSTimer thường xuyên hoạt động với cùng một thời gian chờ. Nó không phải là một vấn đề với việc giữ biến NSTimer, bởi vì nó không hoạt động ngay cả khi tôi mạnh mẽ giữ nó. – Gobe

+0

Tôi đảm bảo với bạn rằng API Cocoa hoạt động. Có thể bạn đang gọi nó bên ngoài luồng chính (hoặc một luồng khác có vòng lặp chạy được cấu hình phù hợp trên đó). – mz2

0

Tôi thích bản hack này @ Peter-Pang !! BlockOperation được tạo ra trên bay, sở hữu bởi Timer mà chính nó là do hàng đợi đang chạy, và gọi bộ chọn chính trên khối để chạy nó .... tốt đẹp !!!

Cập nhật cho Swift 3

Timer.scheduledTimer(timeInterval: 1, target: BlockOperation { // ... }, selector: #selector(Operation.main), userInfo: nil, repeats: false)