El comando de "retraso" de AppleScript no funciona desde que se cambió a Yosemite

10

Nota: El problema con delayse solucionó en OS X 10.11 El Capitan.

Desde que me actualicé a Yosemite, los Applescripts que usan retrasos han dejado de funcionar. ¿Cómo puedo arreglar esto?

Aquí está el Applescript más simple del mundo, en aras de un ejemplo 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

Eso debería tomar 30 segundos en completarse. Si lo ejecuto en Script Editor (anteriormente Applescript Editor), tarda 30 segundos en completarse. Pero si guardo este script como una aplicación, cuando la ejecuto, los retrasos se ignoran y la aplicación tarda una fracción de segundo en completarse.

¿Cómo puedo obligar a Applescript a retrasarse durante un período de tiempo específico antes de pasar al siguiente paso? ¿Es esto un problema técnico de Yosemite? ¿Existe una solución confiable?

2oh1
fuente
Esto funciona como se esperaba en mi Mac (10.10.1)
markhunte
¿Alguna idea de lo que hace que no funcione en la mía? Para aclarar: funciona en Script Editor, pero si guardo el script como una aplicación y luego inicio la aplicación, los retrasos se ignoran. Es lo más extraño.
2oh1
Tengo el mismo problema en 10.10.3
Thomas Tempelmann
Informó a Apple: openradar.me/21588747
Thomas Tempelmann
1
Este problema se solucionó en OS X 10.11 El Capitan.
Chris Page

Respuestas:

7

Nota: El problema con delayse solucionó en OS X 10.11 El Capitan.

@ 2oh1, tiene la idea básica correcta en su respuesta, pero aquí hay una respuesta completa y correcta:

La única forma razonable de evitar esto es invocar un "retraso" dentro de un ciclo que garantice que transcurra la duración deseada antes de continuar. La mejor manera de hacerlo es anular el "retraso" con un controlador 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

Esto le permite dejar el resto de su script sin cambios y puede usar "delay" normalmente, por ejemplo,

delay 5
display alert "I like cake!"

[NOTA: Normalmente, el controlador personalizado usaría "duración de retraso continuo" para invocar el "retraso" incorporado, pero descubrí que, aunque esto funciona dentro del Editor de secuencias de comandos, devuelve un error cuando se usa dentro de un applet ("Can ' t continuar demora. (-1708) "). Resolví ese problema diciéndole directamente a AppleScript que manejara el comando de retraso en lugar de usar "continuar" para llegar allí.]

El problema es que delayprocesa la entrada del usuario al pausar la secuencia de comandos, por lo que aún puede hacer clic en los menús o ventanas que muestra un applet, y hay un error (corregido en 10.11) donde la entrada del usuario hace delayque no espere la duración completa antes de reanudar la ejecución del script . Si no interactúa con el applet, delayfunciona correctamente.

Chris Page
fuente
¿Es todo esto un error, o hay una razón por la cual el retraso funciona de esta manera con Yosemite?
2oh1
Es un error que la demora no demora.
Chris Page
Es tan extraño. Estaba jugando con un applecript que usa delay la otra noche, y de repente, el delay funcionaba correctamente nuevamente. Asumí que el error había sido reparado. Una hora después, aunque nada había cambiado, el error había vuelto. Estoy realmente desconcertado. Aunque no importa. Estoy usando una variable para establecer el tiempo y el retraso hasta cinco minutos después (por ejemplo), y está funcionando perfectamente. Entonces ... problema resuelto, pero eso no explica por qué existe el problema. Interesante, interesante, interesante.
2oh1
1
Porque Apple se burló. El software de Apple es mucho menos confiable desde que comenzaron a lanzar OS X anualmente. Echo de menos las versiones menores de OS X superiores (como 10.6.8) donde el sistema operativo era sólido como una roca. Simplemente ya no tienes ese tipo de experiencia.
William T Froggard
Si se trata de un error (con el que estoy de acuerdo), me pregunto por qué todavía no está solucionado. ¿Alguien aquí ha hecho un informe de radar? Entonces, ¿podría publicar su ID? (o / también publique en openradar.me)
Thomas Tempelmann
5

Mientras luchaba con este mismo problema, encontré esta respuesta a una pregunta no tan relacionada y decidí intentarlo y parece que funciona para mí.

Simplemente reemplace delay 5con do shell script "/bin/sleep 5"y obtenga el mismo resultado.

JCobb
fuente
¡Gracias por compartir! Como dije anteriormente, no puedo probar esto porque, por razones que no tienen sentido para mí, el retraso 5 está funcionando como debería en este momento (lo probé nuevamente hace un momento). No tengo idea de por qué esto a veces funciona y a veces falla. Es tan extraño. Terminé usando una solución alternativa en la que obtengo la hora actual y la configuro como una variable, y luego detengo el script hasta que la hora es variable más un minuto (por un retraso de 1 minuto, obviamente). Es torpe, pero ha funcionado perfectamente durante meses, mientras que un simple retraso ha sido intermitente. Ugh
2oh1
Estoy ejecutando 10.10.5 y esta solución no funciona y también bloquea el script durante la duración del sueño
Greg
@Greg: Si "bloquea el script" durante la duración del sueño, entonces está funcionando. /bin/sleepespera la duración del sueño y no regresa hasta que se haya completado. En contraste, el delaycomando incorporado de AppleScript maneja los eventos de entrada del usuario mientras el script está en pausa. (Que es donde radica el error: si hay entrada de teclado del usuario, delaycontinúa la ejecución del script antes de que se haya completado la duración del retraso.)
Chris Page
3

No digo que esta sea la mejor solución, pero parece haber resuelto mi problema. En lugar de usar un retraso simple, que se ignora por razones que no entiendo, he cambiado a obtener el tiempo y hacer un bucle hasta que se alcanza un nuevo tiempo (todavía usa un retraso, pero no importa si ignora el retraso ya que el script no continúa hasta que se alcanza el tiempo).

# 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

Todavía me muero por saber por qué se ignora la demora (¿o se acelera dramáticamente?!?), Pero esto hace el trabajo, torpe como es.

2oh1
fuente
El comando "retraso" no se está "acelerando", se está interrumpiendo. Mientras se retrasa, se asienta en un bucle para verificar si hay eventos de entrada de teclado para que pueda verificar el período de comando. Aparentemente, está saliendo incorrectamente del bucle de retardo cuando se detecta cualquier entrada del usuario.
Chris Page
¡Interesante! Estoy descubriendo que está siendo ignorado (¿acelerado? ¿Interrumpido?) Incluso cuando mi Mac está inactiva, pero no sé por qué.
2oh1
Una vez que un evento de entrada del usuario está en la cola de eventos, delayse continuará interrumpiendo hasta que algo maneje los eventos y los elimine de la cola.
Chris Page
2

Encontré una solución en una publicación en un foro alemán . Agregue estas líneas a la parte superior de su script:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1
Thomas Tempelmann
fuente
Tengo problemas para probar su respuesta porque, por cualquier razón, el retraso funciona actualmente como se esperaba en mi Mac. No tengo ni idea de porqué. Estoy ejecutando 10.10.3. ¿Quizás Apple solucionó este error? O tal vez es solo un problema intermitente que no está afectando a mi Mac en este momento. Ugh Sin embargo, como dije anteriormente, mi solución consiste en que Applescript obtenga la hora actual y luego se demore hasta la hora actual más x.
2oh1
También estoy ejecutando 10.10.3 y todavía veo el problema. Como no todos ven el problema, es probable que sea intermitente o esté relacionado con software de terceros o con ciertas configuraciones de preferencias. Quién sabe. Por cierto, su solución tiene probablemente la desventaja de que la aplicación sigue usando el 100% del tiempo de CPU mientras espera, mientras que el comportamiento de retraso adecuado es poner la aplicación en suspensión durante ese tiempo, con lo que usa menos energía.
Thomas Tempelmann
Estoy ejecutando 10.10.5 y esta solución no funciona.
Greg
@ThomasTempelmann: El problema ocurre cuando hay una entrada del usuario. Si no hace clic ni escribe mientras se ejecuta el script, el error no se activa.
Chris Page
Tenga en cuenta que esta solución hace que la aplicación se congele durante la duración del sueño. delayprocesa la entrada del usuario mientras el script está en pausa, por lo que aún puede interactuar con menús y ventanas, por ejemplo.
Chris Page
0

carzyj tuvo lo que considero la mejor respuesta, pero cuando se combina con el método de Chris Page, obtienes:

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

Puede comentar "en retraso" a través de "fin de retraso" para volver al retraso original.

Dickster
fuente
También hice una modificación de código similar, antes de ver esto. Estoy ejecutando 10.10.5 y esta solución no funciona y también bloquea el script mientras duerme.
Greg
0

esta es una modificación de la solución @ chris-page

Parece ser un equilibrio entre la capacidad de respuesta y la captura precisa de la demora.

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

Pero en lugar de decirle a Applescript que se demore por la duración total, solo le decimos que se demore por un período fraccional de la duración. Si el período es menor que el que permite Apple (1/60 de segundo), entonces configurémoslo en ese delta. Que podemos mantener cierta capacidad de respuesta, pero aún así ser precisos. la sospecha es que a veces el retraso no funciona, por lo que la repetición del bucle mantendrá el hilo bloqueado, pero en los escenarios de éxito, queremos que el retraso delta sea corto para que el proceso aún se pueda interrumpir

Greg
fuente
Acortar el retraso solicitado es innecesario y solo puede hacer que el script se ejecute más lentamente y consuma más CPU mientras espera. Mi versión simplemente llama al retraso hasta que haya transcurrido toda la duración deseada, lo delayque permite retrasar tanto como sea posible antes de que continúe la ejecución.
Chris Page
Tenga en cuenta que, dado que esta respuesta fue publicada, actualicé mi código para usar en delay endTime - (current date)lugar de delay duration, lo que garantiza que si delay no se interrumpe, no pausará el script por más tiempo que el tiempo solicitado originalmente, que puede haber sido lo que intentaba Dirección con esta respuesta.
Chris Page
0

Entonces, para ponerlo todo junto, creo que Chris quiere decir esto:

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
fuente