Як використовувати NSTimer?


344

Як я можу використовувати NSTimer? Хтось може дати мені покрокові інструкції?


1
я отримав інформацію про параметри на pravinmagdum.wordpress.com/2010/12/30/how-to-use-nstimer подивіться на це .. може бути корисним для вас

Відповіді:


616

По-перше, я хотів би звернути вашу увагу на документацію щодо какао / CF (яка завжди є чудовим першим портом дзвінка). Документи Apple мають розділ у верхній частині кожної довідкової статті під назвою "Посібники по супроводі", де перераховані посібники для документально підтвердженої теми (якщо такі є). Наприклад, з NSTimer, в документації списки двох гідів - компаньйонів:

Для вашої ситуації стаття з теми програмування за таймером, ймовірно, буде найбільш корисною, в той час як теми потоків пов'язані, але не є найбільш безпосередньо пов'язаними з документуванням класу. Якщо ви подивитесь на статтю Теми програмування за таймером, вона розділена на дві частини:

  • Таймери
  • Використання таймерів

Для статей, що приймають цей формат, часто є огляд класу та для чого він використовується, а потім деякий зразок коду про те, як ним користуватися, у цьому випадку в розділі «Використання таймерів». Є розділи на тему: "Створення та планування таймера", "Зупинка таймера" та "Управління пам'яттю". Зі статті, створення запланованого неповторюваного таймера можна зробити приблизно так:

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

Це дозволить створити таймер , який запускається після 2,0 секунд і викликає targetMethod:на selfз одним аргументом, який є покажчиком на NSTimerекземпляр.

Якщо ви хочете детальніше вивчити метод, ви можете звернутися до документів для отримання додаткової інформації, але навколо цього коду є пояснення.

Якщо ви хочете зупинити таймер, який повторюється, (або зупинити неповторюваний таймер до його запуску), тоді вам потрібно тримати покажчик на створений NSTimerекземпляр; часто це потребує змінної примірника, щоб ви могли посилатися на неї в іншому методі. Потім ви можете зателефонувати invalidateв NSTimerекземпляр:

[myTimer invalidate];
myTimer = nil;

Також є хорошою практикою nilвимкнути змінну екземпляра (наприклад, якщо ваш метод, який визнає недійсним таймер, викликається більше одного разу, і змінна екземпляр не встановлено, nilа NSTimerекземпляр розміщений, це призведе до виключення).

Зверніть увагу також на пункт "Керування пам'яттю" внизу статті:

Оскільки цикл запуску підтримує таймер, з точки зору управління пам'яттю зазвичай не потрібно зберігати посилання на таймер після того, як ви його запланували . Оскільки таймер передається як аргумент, коли ви визначаєте його метод як селектор, ви можете визнати недійсним повторюваний таймер, коли це доречно в рамках цього методу . Однак у багатьох ситуаціях ви також бажаєте вимкнути таймер - можливо, ще до його запуску. У цьому випадку вам потрібно зберігати посилання на таймер, щоб ви могли надсилати йому недійсне повідомлення, коли це можливо. Якщо ви створюєте позаплановий таймер (див. "Непланові таймери"), тоді ви повинні підтримувати чітке посилання на таймер (у звітному середовищі, яке ви зберігаєте), щоб він не був розміщений перед його використанням.


Okk, одне запитання, що я вдавав би як свій код, який виконується кожні дві секунди?
lab12

Ви б передати YESдля repeats:коли ви телефонуєте scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:. Якщо ви це зробите, то не забудьте зберегти посилання на NSTimerекземпляр (він повертається методом) та дотримуйтесь пункту управління пам’яттю, як я детально описав вище.
Олексій Розанський

Ні, куди б я поставив свій код, який би починався кожні 2 секунди? Наприклад, скажімо, що я хотів, щоб кожні 2 секунди видавали звуковий сигнал. куди б я поставив звуковий сигнал ..?
lab12

У способі, який ви вказуєте за допомогою targetі selector. Наприклад, якщо ваша ціль є, selfа селектор - timerMethod:метод, який називається, коли таймер спрацьовує timerMethod:у програмі self. Потім ви можете ввести який-небудь код, який ви хочете в цьому методі, і метод буде викликатися, коли таймер запускається. Зауважте, що метод, викликаний при запуску таймера (який ви selector:передаєте як " ), може приймати лише один аргумент (який при виклику є вказівником на NSTimerекземпляр).
Олексій Розанський

Вибачте, мав на увазі "визначено на self"
Алекс Розанський

331

є кілька способів використання таймера:

1) запланований таймер та використання селектора

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • якщо встановити повтори на "НІ", таймер зачекає 2 секунди перед запуском селектора і після цього він зупиниться;
  • якщо повторити: ТАК, таймер почнеться негайно та повторюватиме виклик селектора кожні 2 секунди;
  • щоб зупинити таймер, який ви викликаєте метод -invalidate таймера: [t недійсний];

Як бічна примітка, замість того, щоб використовувати таймер, який не повторюється, і викликати селектор через визначений інтервал, ви можете використовувати просту заяву на зразок цього:

[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];

це матиме такий же ефект, як і зразок коду, наведеного вище; але якщо ви хочете викликати селектор щоразу в n-й раз, ви використовуєте таймер з повторами: ТАК;

2) таймер самопланування

NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
                              interval: 1
                              target: self
                              selector:@selector(onTick:)
                              userInfo:nil repeats:YES];

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
  • це створить таймер, який запуститься у вказану вами власну дату (в цьому випадку через хвилину) і повторюватиметься щосекунди

3) позаплановий таймер та використання виклику

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
                      invocation:inv 
                      repeats:YES];

і після цього ви запускаєте таймер вручну, коли вам потрібно:

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];



І як зауваження, метод onTick: виглядає так:

-(void)onTick:(NSTimer *)timer {
   //do smth
}

Гаразд, але ви бачите, що я хочу знизити прозорість свого додатка, тому я не знаю, як це застосувати за допомогою NSTimer
lab12,

24
Боже, ці люди сьогодні .. голосуй від мене, бо ти не вказав це з самого початку і дай нам писати даремно!
Woofy

28
Ви не писали даремно. Це ДОБРА інформація!
willc2

У способі 2 "Таймер самопланування", як я можу зупинити таймер, коли хочу?
Сатьям

1
@Satyamsvv, ви можете зупинити таймер шляхом виклику, скажімо, іншого методу, який має: [таймер недійсний]; таймер = нуль;
Кімпой

59

Щось на зразок цього:

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];

14
Ще сильний ... 2014 теж!
Muruganandham K

5
#import "MyViewController.h"

@interface MyViewController ()

@property (strong, nonatomic) NSTimer *timer;

@end

@implementation MyViewController

double timerInterval = 1.0f;

- (NSTimer *) timer {
    if (!_timer) {
        _timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
    }
    return _timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

-(void)onTick:(NSTimer*)timer
{
    NSLog(@"Tick...");
}

@end

Так чи інакше це створює цикл утримування, тому MyViewControllerніколи не відбувається розселення.
Даррарський

5
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}

де ти це написав?
Мохіт

1
@JigneshB ця відповідь стосується лише того, як використовувати NSTimer, а не використовувати його у фоновому режимі
Mohit

я писав у фоновому методі, тобто - (недійсна) applicationDidEnterBackground: (UIApplication *) додаток {}
Jignesh B

з повторним режимом ТАК
Jignesh B

Документація Apple дуже специфічна щодо підпису методу зворотного дзвінка. Ваше помиляється.
Микола Рухе

2

У відповідях відсутній конкретний таймер дня, ось наступна година:

NSCalendarUnit allUnits = NSCalendarUnitYear   | NSCalendarUnitMonth |
                          NSCalendarUnitDay    | NSCalendarUnitHour  |
                          NSCalendarUnitMinute | NSCalendarUnitSecond;

NSCalendar *calendar = [[ NSCalendar alloc]  
                          initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *weekdayComponents = [calendar components: allUnits 
                                                  fromDate: [ NSDate date ] ];

[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];

NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];

refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
                                          interval: 0.0
                                            target: self
                                          selector: @selector( doRefresh )
                                          userInfo: nil repeats: NO ];

[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];

Звичайно, замініть "doRefresh" бажаним методом вашого класу

спробуйте створити об’єкт календаря один раз і зробіть allUnits статичним для ефективності.

додавання одного годинного компонента працює чудово, не потрібно тестування опівночі ( посилання )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.