O comando “delay” do AppleScript não funciona desde a mudança para Yosemite

10

Nota: O problema com delayfoi corrigido no OS X 10.11 El Capitan.

Desde que atualizei para o Yosemite, os scripts de maçã que usam atrasos pararam de funcionar. Como posso consertar isso?

Aqui está o Applescript mais simples do mundo, para um exemplo fácil:

set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0

Isso deve levar 30 segundos para ser concluído. Se eu executá-lo no Script Editor (anteriormente Applescript Editor), leva 30 segundos para ser concluído. Porém, se eu salvar esse script como um aplicativo, ao iniciá-lo, os atrasos serão ignorados e o aplicativo levará uma fração de segundo para ser concluído.

Como forçar o Applescript a adiar por um período especificado antes de prosseguir para a próxima etapa? Esta é uma falha de Yosemite? Existe uma solução alternativa confiável?

2oh1
fonte
Isso funciona como esperado no meu Mac (10.10.1)
markhunte
Alguma idéia do que faz com que não funcione na minha? Para esclarecer: ele funciona no Editor de scripts, mas se eu salvar o script como um aplicativo e iniciá-lo, os atrasos serão ignorados. É a coisa mais estranha.
precisa
Eu tenho o mesmo problema em 10.10.3
Thomas Tempelmann
Relatado à Apple: openradar.me/21588747
Thomas Tempelmann
1
Esse problema foi corrigido no OS X 10.11 El Capitan.
Chris Página

Respostas:

7

Nota: O problema com delayfoi corrigido no OS X 10.11 El Capitan.

@ 2oh1, você tem a idéia básica certa em sua resposta, mas aqui está uma resposta completa e correta:

A única maneira razoável de contornar isso é invocar o "atraso" dentro de um loop que garante a duração desejada antes de continuar. A melhor maneira de fazer isso é substituir o "atraso" por um manipulador personalizado:

on delay duration
  set endTime to (current date) + duration
  repeat while (current date) is less than endTime
    tell AppleScript to delay endTime - (current date)
  end repeat
end delay

Isso permite que você mantenha o restante do seu script inalterado e você pode usar o "atraso" normalmente, por exemplo,

delay 5
display alert "I like cake!"

[OBSERVAÇÃO: Normalmente, o manipulador personalizado usaria "continue delay duration" para chamar o "delay" interno, mas descobri que, embora isso funcione no Editor de scripts, ele retorna um erro quando usado em um applet ("Pode" t continue o atraso. (-1708) "). Eu resolvi esse problema dizendo diretamente ao AppleScript para manipular o comando delay em vez de usar "continue" para chegar lá.]

O problema é que delayprocessa a entrada do usuário durante a pausa do script, para que você ainda possa clicar nos menus ou janelas exibidos por um applet, e há um erro (corrigido no 10.11) em que a entrada do usuário faz delaycom que não espere a duração total antes de continuar a execução do script . Se você não interagir com o applet, delayfuncionará corretamente.

Chris Page
fonte
Tudo isso é um bug ou existe um motivo pelo qual o atraso está funcionando dessa maneira com o Yosemite?
2oh1
É um erro que o atraso não está atrasando.
Chris Page
É tão estranho. Eu estava mexendo com um manuscrito que usa atraso na outra noite e, de repente, o atraso estava funcionando corretamente novamente. Eu assumi que o bug havia sido corrigido. Uma hora depois, mesmo que nada tivesse mudado, o bug estava de volta. Estou verdadeiramente perplexo. Não importa. Estou usando uma variável para definir a hora e o atraso até cinco minutos depois (por exemplo), e está funcionando perfeitamente. Então ... problema resolvido, mas isso não explica por que o problema existe. Interessante, interessante, interessante.
01h15 de
1
Porque a Apple brincou. O software da Apple é muito menos confiável desde que começaram a lançar o OS X anualmente. Sinto falta das versões secundárias superiores do OS X (como 10.6.8), nas quais o sistema operacional era sólido. Você simplesmente não tem mais esse tipo de experiência.
William T Froggard
Se é um bug (com o qual concordo), por que isso ainda não está corrigido, eu me pergunto. Alguém aqui fez um relatório de radar? Em seguida, você poderia postar seu ID? (ou também postar em openradar.me)
Thomas Tempelmann
5

Enquanto lutava contra esse mesmo problema, me deparei com essa resposta para uma pergunta não tão relacionada e decidi tentar e parece funcionar para mim.

Simplesmente substitua delay 5por do shell script "/bin/sleep 5"e obtenha o mesmo resultado.

JCobb
fonte
Obrigado por compartilhar! Como eu disse anteriormente, não consigo testar isso porque, por razões que não fazem sentido para mim, o atraso 5 está funcionando como deveria para mim agora (acabei de testar novamente há pouco). Não tenho ideia de por que isso às vezes funciona e às vezes falha. É tão estranho. Acabei usando uma solução alternativa em que obtenho o horário atual e o defini como variável e, em seguida, pause o script até que o tempo seja variável mais um minuto (por um minuto, obviamente). É desajeitado, mas funcionou perfeitamente durante meses, enquanto um simples atraso foi intermitente. Ugh.
2oh1
Estou executando o 10.10.5 e esta solução não funciona e também bloqueia o script pela duração do sono.
Greg
@ Greg: Se "bloqueia o script" pela duração do sono, está funcionando. /bin/sleepaguarda a duração do sono e não retorna até que seja concluído. Por outro lado, o delaycomando interno do AppleScript lida com eventos de entrada do usuário enquanto o script está em pausa. (Que é onde as mentiras de bugs: se houver entrada de teclado do usuário, delaycontinua a execução do script antes de a duração de atraso foi concluída.)
Chris Página
3

Não estou dizendo que esta é a melhor solução, mas parece que resolveu meu problema. Em vez de usar um atraso simples, que está sendo ignorado por razões que não entendo, mudei para obter o tempo e fazer um loop até chegar um novo horário (ele ainda usa um atraso, mas não importa se ignora o atraso, já que o script não continua até a hora chegar).

# Pause for five minutes
set GetTheTime to current date
set NewTime to GetTheTime + (5 * minutes)
repeat while (current date) is less than NewTime
    delay 60
end repeat

Ainda estou morrendo de vontade de saber por que o atraso está sendo ignorado (ou acelerado dramaticamente?! ??), mas isso faz o trabalho, por mais desajeitado que seja.

2oh1
fonte
O comando "delay" não está sendo "acelerado", está sendo interrompido. Enquanto atrasa, ele fica em loop verificando se há algum evento de entrada do teclado para que possa verificar o Período do Comando. Aparentemente, ele está saindo incorretamente do loop de atraso quando qualquer entrada do usuário é detectada.
25415 Chris Page
Interessante! Estou descobrindo que ele está sendo ignorado (acelerado? Interrompido?) Mesmo quando meu Mac está ocioso, mas não sei por quê.
01h15 15/03
Quando um evento de entrada do usuário estiver na fila de eventos, delaycontinuará sendo interrompido até que algo lide com os eventos e os remova da fila.
Chris Página
2

Encontrei uma solução alternativa em um post no fórum alemão . Adicione estas linhas na parte superior do seu script:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1
Thomas Tempelmann
fonte
Estou tendo problemas para testar sua resposta porque, por qualquer motivo, o atraso está funcionando como esperado no meu Mac. Eu não tenho ideia do porquê. Estou executando o 10.10.3. Talvez a Apple tenha corrigido esse bug? Ou talvez seja apenas um problema intermitente que não está afetando meu Mac no momento. Ugh. Como eu disse acima, porém, minha solução alternativa é fazer com que o Applescript obtenha a hora atual e adie até a hora atual mais x.
2oh1
Também estou executando o 10.10.3 e ainda vejo o problema. Como nem todo mundo vê o problema, provavelmente é intermitente ou relacionado a software de terceiros ou a determinadas configurações de preferência. Quem sabe. BTW, sua solução alternativa provavelmente tem a desvantagem de o aplicativo continuar usando 100% do tempo de CPU enquanto aguarda, enquanto o comportamento de atraso adequado é colocar o aplicativo em suspensão por esse período, consumindo menos energia.
Thomas Tempelmann
Estou executando o 10.10.5 e esta solução não funciona.
Greg
@ThomasTempelmann: o problema ocorre quando há entrada do usuário. Se você não clicar ou digitar enquanto o script estiver em execução, o bug não será acionado.
Chris Página
Observe que esta solução faz com que o aplicativo realmente congele durante a duração do sono. delayprocessa a entrada do usuário enquanto o script está em pausa, para que você ainda possa interagir com menus e janelas, por exemplo.
Chris Página
0

carzyj teve o que considero a melhor resposta, mas quando combinado com o método de Chris Page, você obtém:

on delay duration
  do shell script "/bin/sleep " & duration
end delay

Você pode comentar "em atraso" a "atraso final" para reverter para o atraso original.

Dickster
fonte
Também fiz uma modificação de código semelhante, antes de ver isso. Estou executando o 10.10.5 e esta solução não funciona e também bloqueia o script durante o sono.
Greg
0

esta é uma modificação na solução @ chris-page

Parece haver um equilíbrio entre a capacidade de resposta e a captura precisa do atraso.

on delay duration
    set endTime to (current date) + duration
    repeat while (current date) is less than endTime
        set delta to duration / 100
        if duration < 0.2 then
            set delta to 0.2
        end if
        tell AppleScript to delay delta
    end repeat
end delay

Mas, em vez de dizer ao Applescript para adiar a duração geral, apenas pedimos que adie por um período fracionário da duração. se o período for menor do que o permitido pela maçã (1/60 de segundo), vamos configurá-lo para esse delta. Que podemos manter alguma capacidade de resposta, mas ainda assim sermos precisos. a suspeita é que, às vezes, o atraso não funcione, e o loop repeat while manterá o encadeamento bloqueado, mas em cenários de sucesso, queremos que o delta do atraso seja curto para que o processo ainda possa ser interrompido

Greg
fonte
Reduzir o atraso solicitado é desnecessário e só pode tornar o script mais lento e consumir mais CPU enquanto aguarda. Minha versão apenas chama atraso até que toda a duração desejada termine, permitindo delayatrasar o máximo possível antes de continuar a execução.
Chris Página
Observe que desde que esta resposta foi publicada, atualizei meu código para usar em delay endTime - (current date)vez de delay duration, o que garante que, se delay não for interrompido, ele não pausará o script por mais tempo do que o pedido originalmente, o que pode ter sido o que você estava tentando endereço com esta resposta.
Chris Page
0

Então, para juntar tudo, acredito que Chris quer dizer isso:

on delay duration
   set endTime to (current date) + duration
   repeat while (current date) is less than endTime
      tell AppleScript to delay endTime - (current date)
   end repeat
end delay
Dick.Guertin
fonte