mas e se você quiser alternar entre as visualizações? O código vai parar certo?
Cing de
5
@Cing depende do que está se referindo.
Antzi,
1
Não se esqueça de que NSTimerretém seu destino, então, com essa configuração, se helloWorldTimeré uma propriedade selfvocê tem um ciclo de retenção, onde selfretém helloWorldTimere helloWorldTimerretém self.
MANIAK_dobrii
@MANIAK_dobrii Você também pode comentar como quebrar o ciclo de retenção? Se o VC for dispensado, mas o cronômetro não cancelado, o ciclo ainda está intacto? Portanto, você deve cancelar o cronômetro e, em seguida, descartar a visualização para interromper o ciclo?
Dave G
1
Para Swift 4, o método do qual você deseja obter o seletor deve ser exposto ao Objective-C, portanto, o atributo @objc deve ser adicionado à declaração do método. por exemplo, `` `@objc func sayHello () {}` ``
Shamim Hossain
136
Se tiver como objetivo a versão 10 e superior do iOS, você pode usar a renderização baseada em bloco de Timer, que simplifica os ciclos de referência fortes em potencial, por exemplo:
weakvar timer:Timer?func startTimer(){
timer?.invalidate()// just in case you had existing `Timer`, `invalidate` it before we lose our reference to it
timer =Timer.scheduledTimer(withTimeInterval:60.0, repeats:true){[weakself]_in// do something here
}}func stopTimer(){
timer?.invalidate()}// if appropriate, make sure to stop your timer in `deinit`
deinit{
stopTimer()}
Embora Timerseja geralmente melhor, para fins de integridade, devo observar que você também pode usar o temporizador de despacho, que é útil para agendar temporizadores em threads de fundo. Com temporizadores de despacho, uma vez que são baseados em blocos, evita alguns dos desafios do ciclo de referência forte com o antigo target/ selectorpadrão de Timer, desde que você use weakreferências.
Assim:
var timer:DispatchSourceTimer?func startTimer(){let queue =DispatchQueue(label:"com.domain.app.timer")// you can also use `DispatchQueue.main`, if you want
timer =DispatchSource.makeTimerSource(queue: queue)
timer!.schedule(deadline:.now(), repeating:.seconds(60))
timer!.setEventHandler {[weakself]in// do whatever you want here
}
timer!.resume()}func stopTimer(){
timer?.cancel()
timer =nil}deinit{self.stopTimer()}
Para mais informações, consulte o a um temporizador Criando secção de Exemplos dispatch Fonte no despacho Fontes seção do Guia de Programação Concorrência.
como você escolheria um cronômetro de execução apenas uma vez dentro dessa abordagem?
Juan Boero
@JuanPabloBoero - Eu não usaria essa abordagem para situações de incêndio único. Você usaria dispatch_after. Ou uma não repetição NSTimer.
Rob
@Rob Eu tenho um rótulo de contador na tela que é atualizado a cada segundo de uma função e estou usando o código acima para incrementar meu contador e atualizar o texto do rótulo. Porém, o problema que estou enfrentando é que minha variável de contador é atualizada a cada segundo, mas a tela não mostra o valor de contador mais recente em meu UILabel.
Nagendra Rao
Rao, o descrito acima é útil para realizar alguma ação em um thread de segundo plano. Mas as atualizações da interface do usuário devem acontecer na fila principal. Portanto, agende isso no thread principal ou pelo menos despache as atualizações da IU de volta para o thread principal.
Rob
1
Esta questão não pertence aqui nos comentários a esta resposta. Exclua seus comentários acima e poste sua própria pergunta. Mas, em resumo, geralmente você não mantém o aplicativo em execução em segundo plano, apenas faz com que pareça que estava. Consulte stackoverflow.com/a/31642036/1271826 .
Rob
17
Aqui está uma atualização para a NSTimerresposta, para Swift 3 (no qual NSTimerfoi renomeado para Timer) usando um encerramento em vez de uma função nomeada:
var timer =Timer.scheduledTimer(withTimeInterval:60, repeats:true){(_)in
print("Hello world")}
Se você pode permitir algum desvio de tempo, aqui está uma solução simples executando algum código a cada minuto:
privatefunc executeRepeatedly(){// put your code here
DispatchQueue.main.asyncAfter(deadline:.now()+60.0){[weakself]inself?.executeRepeatedly()}}
Basta executar executeRepeatedly()uma vez e ele será executado a cada minuto. A execução para quando o objeto proprietário ( self) é liberado. Você também pode usar um sinalizador para indicar que a execução deve parar.
let timer :DispatchSourceTimer=DispatchSource.makeTimerSource(flags:[], queue:DispatchQueue.main)
timer.scheduleRepeating(deadline:.now(), interval:.seconds(60))
timer.setEventHandler
{NSLog("Hello World")}
timer.resume()
Isso é especialmente útil quando você precisa despachar em uma fila específica. Além disso, se você está planejando usar isso para atualização da interface do usuário, sugiro olhar CADisplayLinkcomo está sincronizado com a taxa de atualização da GPU.
Respostas:
Lembre-se de importar a Fundação.
Swift 4:
fonte
NSTimer
retém seu destino, então, com essa configuração, sehelloWorldTimer
é uma propriedadeself
você tem um ciclo de retenção, ondeself
retémhelloWorldTimer
ehelloWorldTimer
retémself
.Se tiver como objetivo a versão 10 e superior do iOS, você pode usar a renderização baseada em bloco de
Timer
, que simplifica os ciclos de referência fortes em potencial, por exemplo:Embora
Timer
seja geralmente melhor, para fins de integridade, devo observar que você também pode usar o temporizador de despacho, que é útil para agendar temporizadores em threads de fundo. Com temporizadores de despacho, uma vez que são baseados em blocos, evita alguns dos desafios do ciclo de referência forte com o antigotarget
/selector
padrão deTimer
, desde que você useweak
referências.Assim:
Para mais informações, consulte o a um temporizador Criando secção de Exemplos dispatch Fonte no despacho Fontes seção do Guia de Programação Concorrência.
Para Swift 2, consulte a revisão anterior desta resposta .
fonte
dispatch_after
. Ou uma não repetiçãoNSTimer
.Aqui está uma atualização para a
NSTimer
resposta, para Swift 3 (no qualNSTimer
foi renomeado paraTimer
) usando um encerramento em vez de uma função nomeada:fonte
Se você pode permitir algum desvio de tempo, aqui está uma solução simples executando algum código a cada minuto:
Basta executar
executeRepeatedly()
uma vez e ele será executado a cada minuto. A execução para quando o objeto proprietário (self
) é liberado. Você também pode usar um sinalizador para indicar que a execução deve parar.fonte
Você pode usar
Timer
(swift 3)Em selector () você coloca o nome da sua função
fonte
Timer
...NSTimer
foi renomeadoNo swift 3.0, o GCD foi refatorado:
Isso é especialmente útil quando você precisa despachar em uma fila específica. Além disso, se você está planejando usar isso para atualização da interface do usuário, sugiro olhar
CADisplayLink
como está sincronizado com a taxa de atualização da GPU.fonte