2013-02-17 4 views
38

Я хочу иметь возможность планировать три небольших события в будущем без необходимости писать функцию для каждого. Как это сделать, используя NSTimer? Я понимаю, что блоки упрощают анонимные функции, но могут ли они использоваться в пределах NSTimer, и если да, то как?NSTimer с анонимной функцией/блоком?

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

Почему вы не используете 'dispatch_after()'? Это функция GCD и принимает блок как параметр. –

+0

Никогда не слышал об этом ... Как мне это использовать?Пока я могу сказать: «Подождите X секунд, а затем сделайте это», я счастлив! – Chris

+1

как насчет '-performSelector: withObject: afterDelay:' метод? – holex

ответ

22

Вы действительно можете позвонить:

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

Используйте это так:

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

+0

Это фантастика. Благодарю. –

+0

Быстро и просто. Прекрасно работает. Благодаря! – Vitalii

+0

Это должен быть выбранный ответ, так как он допускает недействительность таймера, который не принят принятым ответом. –

56

Вы можете использовать dispatch_after, если хотите достичь чего-то подобного NSTimer и выполнить блок.

Вот пример код для тех же:

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. 

    }); 

Надеется, что это помогает.

+9

Примечание! Вы использовали int64_t для задержки в секундах, так что это будет работать только целые числа секунд! gameInterval, я предполагаю, меньше 1 секунды, так что это не будет делать то, что вы хотите. (Шаблон Xcode для этого довольно обманчив.) –

+1

Джесси прав. Обратите внимание, что фактический параметр принимает значение, измеренное в * наносекундах *, хотя, следовательно, константу 'NSEC_PER_SEC'. Таким образом, вы можете указать доли секунды, но вам нужно быть осторожными с вашими числовыми типами. Что-то вроде '(int64_t) (gameInterval * (double) NSEC_PER_SEC)' где 'gameInterval' является' double' должен работать. – devios1

+1

Сообщение спрашивает, как это сделать с помощью NSTimer. Я не могу аннулировать использование dispatch_after. – circuitry

6

Это довольно просто, но он не включен в структуру Apple, по крайней мере пока.

Вы можете написать обертки на основе блоков для NSTimer самостоятельно, например. используя GCD, или вы можете использовать существующие сторонние библиотеки, такие как этот: https://github.com/jivadevoe/NSTimer-Blocks.

7

Objective-C версия ответа @Peter Пэна:

_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 (от прошивкой 10+/MacOS 10.12+) - вот как вы можете использовать его в Swift 3:

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

... или в Objective-C:

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

Если вам нужно ориентироваться на версии ОС старше iOS10, macOS 12, tvOS 10, watchOS 3, вы должны использовать одно из других решений.

+1

Я был рад узнать об этом дополнении недавно. Учитывая, что у нас были блоки с iOS 4, это удивительно, что Apple до тех пор, пока iOS 10 не бросит в блок-интерфейс API для NSTimer! –

+1

Удивительно, но это не работает для меня, по крайней мере, в Objective-C. Блок просто не вызван. Это не проблема с таймаутом, потому что регулярная инициализация NSTimer работает с тем же таймаутом. Это не проблема с переносом переменной NSTimer, потому что она не работает, даже если я ее сильно удерживаю. – Gobe

+0

Уверяю вас, что работает Cocoa API. Вероятно, вы вызываете его вне основного потока (или другого потока, который имеет на нем подходящий цикл выполнения). – mz2

0

Мне нравится этот хак @ Peter-Pang !! BlockOperation создается «на лету», собственный таймер, который сам по себе принадлежит к запущенной очереди, и вызывает основной селектор на блоке, чтобы запустить его.

Обновлено для Swift 3

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