как мне использовать nstimer?

<p>как мне использовать <code>nstimer</code>? кто-нибудь может дать мне пошаговые инструкции?</p>

<p>во-первых, я хотел бы обратить ваше внимание на документацию по cocoa/cf (которая всегда является отличным первым портом захода). в документах apple в верхней части каждой справочной статьи есть раздел под названием "руководства для сопровождающих", в котором перечислены руководства для документируемой темы (если таковые имеются). например, с <code>nstimer</code>, <a href="http://developer.apple.com/mac/library/documentation/cocoa/reference/foundation/classes/nstimer\_class/reference/nstimer.html">документация</a> перечисляет два сопутствующих руководства:</p><ul> <li> <a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/timers/index.html#//apple\_ref/doc/uid/10000061i">темы программирования таймера для какао</a> </li> <li> <a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/multithreading/index.html#//apple\_ref/doc/uid/10000057i">руководство по программированию потоков</a> </li> </ul><p>в вашей ситуации статья "темы программирования таймера", вероятно, будет наиболее полезной, хотя темы с потоками связаны, но не имеют непосредственного отношения к документируемому классу. если вы посмотрите на статью "темы программирования таймера", она разделена на две части:</p><ul> <li>таймеры</li> <li>использование таймеров</li> </ul><p>для статей, принимающих этот формат, часто есть обзор класса и того, для чего он используется, а затем некоторый пример кода <em> как </em> его использовать, в данном случае в " использование таймеров ". существуют разделы "создание и планирование таймера", "остановка таймера" и "управление памятью". из этой статьи создание запланированного неповторяющегося таймера можно сделать примерно так:</p><pre><code>[nstimer scheduledtimerwithtimeinterval:2.0 target:self selector:@selector(targetmethod:) userinfo:nil repeats:no]; </code></pre><p>это создаст таймер, который срабатывает через 2,0 секунды и вызывает <code>targetmethod:</code> для <code>self</code> с одним аргументом, который является указателем на экземпляр <code>nstimer</code>.</p><p>если затем вы хотите более подробно взглянуть на метод, вы можете обратиться к документации для получения дополнительной информации, но есть и объяснения вокруг кода.</p><p>если вы хотите остановить повторяющийся таймер (или остановить неповторяющийся таймер до его запуска), вам нужно сохранить указатель на созданный экземпляр <code>nstimer</code>; часто это должна быть переменная экземпляра, чтобы вы могли ссылаться на нее в другом методе. затем вы можете вызвать <code>invalidate</code> в экземпляре <code>nstimer</code>:</p><pre><code>[mytimer invalidate]; mytimer = nil; </code></pre><p>также хорошей практикой является <code>nil</code> из переменной экземпляра (например, если ваш метод, который делает недействительным таймер, вызывается более одного раза, а переменной экземпляра не было присвоено значение <code>nil</code> и экземпляр <code>nstimer</code> был освобожден, он вызовет исключение) ,.</p><p>обратите также внимание на пункт "управление памятью" в нижней части статьи:</p><blockquote> <p>поскольку цикл выполнения поддерживает таймер, с точки зрения управления памятью <strong> обычно нет необходимости сохранять ссылку на таймер после того, как вы запланировали его </strong>. поскольку таймер передается в качестве аргумента, когда вы указываете его метод в качестве селектора, <strong> вы можете сделать недействительным повторяющийся таймер, когда это уместно в этом методе </strong>. однако во многих ситуациях вы также хотите отключить таймер - возможно, даже до его запуска. <strong> в этом случае вам необходимо сохранить ссылку на таймер, чтобы вы могли отправлять ему сообщение о недействительности в любое время </strong>. если вы создаете незапланированный таймер (см. "незапланированные таймеры"), то вы должны поддерживать надежную ссылку на таймер (в среде с подсчетом ссылок вы сохраняете его), чтобы он не был освобожден перед его использованием.</p> </blockquote>

<p>есть несколько способов использования таймера:</p><p>1) <b>запланированный таймер и использование селектора</b></p><pre><code>nstimer *t = [nstimer scheduledtimerwithtimeinterval: 2.0 target: self selector:@selector(ontick:) userinfo: nil repeats:no]; </code></pre><ul> <li>если вы установите повторы на no, таймер будет ждать 2 секунды, прежде чем запустить селектор, и после этого он остановится;</li> <li>если повторить: да, таймер запустится немедленно и будет повторять вызов селектора каждые 2 секунды;</li> <li>чтобы остановить таймер, вы вызываете метод -invalidate для таймера: [t invalidate];</li> </ul><p>в качестве примечания, вместо использования таймера, который не повторяется и вызывает селектор после указанного интервала, вы можете использовать простое утверждение, подобное этому:</p><pre><code>[self performselector:@selector(ontick:) withobject:nil afterdelay:2.0]; </code></pre><p>это будет иметь тот же эффект, что и пример кода выше; но если вы хотите вызывать селектор каждый раз, вы используете таймер с повторениями: yes;<br> <br></p><p>2) <b>таймер</b></p><pre><code>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]; </code></pre><ul> <li>это создаст таймер, который запустится в определенную вами дату (в данном случае через минуту) и будет повторяться каждую секунду<br> <br></li> </ul><p>3) <b>внеплановый таймер и использование вызова</b></p><pre><code>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]; </code></pre><p>и после этого вы запускаете таймер вручную всякий раз, когда вам нужно:</p><pre><code>nsrunloop *runner = [nsrunloop currentrunloop]; [runner addtimer: t formode: nsdefaultrunloopmode]; </code></pre><p><br> <br> и как примечание, метод ontick: выглядит следующим образом:</p><pre><code>-(void)ontick:(nstimer *)timer { //do smth } </code></pre>

<p>что-то вроде этого:</p><pre><code>nstimer *timer; timer = [nstimer scheduledtimerwithtimeinterval: 0.5 target: self selector: @selector(handletimer:) userinfo: nil repeats: yes]; </code></pre>

<pre><code>nstimer *timer = [nstimer scheduledtimerwithtimeinterval:60 target:self selector:@selector(timercalled) userinfo:nil repeats:no]; -(void)timercalled { nslog(@"timer called"); // your code } </code></pre>

<pre><code>#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 </code></pre>

<p>в ответах не хватает определенного времени, таймер дня здесь на следующий час:</p><pre><code>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]; </code></pre><p>конечно, замените "dorefresh" желаемым методом вашего класса</p><p>попытайтесь создать объект календаря один раз и сделайте allunits статическим для эффективности.</p><p>добавление компонента "один к часу" работает просто отлично, тест полуночи не требуется ( <a href="https://stackoverflow.com/questions/2309337/nsdate-for-beginning-of-next-hour">ссылка</a> )</p>