Il comando "delay" di AppleScript non funziona dal momento che passa a Yosemite


10

Nota: il problema con è delaystato risolto in OS X 10.11 El Capitan.

Da quando ho effettuato l'aggiornamento a Yosemite, gli script di Apple che utilizzano i ritardi hanno smesso di funzionare. Come posso risolvere questo problema?

Ecco l'applescript più semplice del mondo, per un semplice esempio:

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

Il completamento dovrebbe richiedere 30 secondi. Se lo eseguo in Script Editor (precedentemente Applescript Editor) ci vogliono 30 secondi per completarlo. Ma se salvo questo script come app, quando avvio l'app, i ritardi vengono ignorati e l'app richiede una frazione di secondo per essere completata.

Come posso forzare Applescript a ritardare per un determinato periodo di tempo prima di passare al passaggio successivo? Questo è un problema tecnico di Yosemite? Esiste una soluzione affidabile?


Funziona come previsto sul mio Mac (10.10.1)
markhunte,

Qualche idea su cosa non lo fa funzionare sul mio? Per chiarire: funziona in Script Editor, ma se salvo lo script come app e quindi lancio l'app, i ritardi vengono ignorati. È la cosa più strana.
2oh1

Ho lo stesso problema il 10.10.3
Thomas Tempelmann il


1
Questo problema è stato risolto in OS X 10.11 El Capitan.
Chris Page

Risposte:


7

Nota: il problema con è delaystato risolto in OS X 10.11 El Capitan.

@ 2oh1, hai la giusta idea di base nella tua risposta, ma ecco una risposta completa e corretta:

L'unico modo ragionevole per aggirare questo problema è invocare il "ritardo" all'interno di un ciclo che garantisca la durata desiderata prima di continuare. Il modo migliore per farlo è quello di sovrascrivere il "ritardo" con un gestore personalizzato:

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

Ciò ti consente di lasciare invariato il resto dello script e di utilizzare normalmente "delay", ad es.

delay 5
display alert "I like cake!"

[NOTA: normalmente, il gestore personalizzato userebbe "continua durata del ritardo" per invocare il "ritardo" incorporato, ma ho scoperto che, sebbene funzioni all'interno di Script Editor, restituisce un errore se utilizzato in un'applet ("Can" t continua il ritardo. (-1708) "). Ho risolto il problema dicendo direttamente ad AppleScript di gestire il comando delay invece di usare "continue" per arrivarci.]

Il problema è che delayelabora l'input dell'utente durante la pausa dello script, quindi puoi ancora fare clic su menu o finestre visualizzate da un'applet e c'è un bug (risolto in 10.11) in cui l'input dell'utente fa sì delayche non attenda la durata completa prima di riprendere l'esecuzione dello script . Se non interagisci con l'applet, delayfunziona correttamente.


Tutto questo è un bug o c'è un motivo per cui il ritardo sta funzionando in questo modo con Yosemite?
2oh1,

È un bug che il ritardo non sta ritardando.
Pagina Chris

È così strano Stavo armeggiando con uno script di mele che usa il ritardo l'altra sera e improvvisamente il ritardo funzionava di nuovo correttamente. Ho pensato che il bug fosse stato corretto. Un'ora dopo, anche se non era cambiato nulla, il bug era tornato. Sono davvero sconcertato. Non importa però. Sto usando una variabile per impostare l'ora e il ritardo fino a cinque minuti dopo (ad esempio), e funziona perfettamente. Quindi ... problema risolto, ma questo non spiega perché il problema esiste. Interessante, interessante, interessante.
2oh1

1
Perché Apple ha preso in giro. Il software Apple è molto meno affidabile da quando hanno iniziato a rilasciare OS X ogni anno. Mi mancano le versioni minori di OS X superiore (come 10.6.8) in cui il sistema operativo era solido. Non hai più questo tipo di esperienza.
William T Froggard,

Se è un bug (con cui sono d'accordo), perché non è ancora non risolto, mi chiedo. Qualcuno qui ha fatto una segnalazione radar? Vuoi quindi pubblicare il suo ID? (o / anche post su openradar.me)
Thomas Tempelmann,

5

Mentre combattevo lo stesso problema mi sono imbattuto in questa risposta a una domanda non così correlata e ho deciso di provarlo e sembra funzionare per me.

Sostituisci semplicemente delay 5con do shell script "/bin/sleep 5"e ottieni lo stesso risultato.


Grazie per la condivisione! Come ho detto prima, non sono in grado di testarlo perché, per motivi che non hanno senso per me, il ritardo 5 funziona come dovrebbe per me in questo momento (l'ho appena provato di nuovo un momento fa). Non ho idea del perché a volte funzioni e talvolta non riesca. È così strano Ho finito per usare una soluzione alternativa in cui ottengo l'ora corrente e la imposto come variabile, quindi metto in pausa lo script fino a quando l'ora è variabile più un minuto (ovviamente per un ritardo di 1 minuto). È goffo, ma ha funzionato perfettamente per mesi, mentre un semplice ritardo è stato intermittente. Ugh.
2oh1,

Sono in esecuzione 10.10.5 e questa soluzione non funziona e blocca anche lo script per la durata del sonno
Greg

@Greg: se "blocca lo script" per la durata del sonno, allora funziona. /bin/sleepattende la durata del sonno e non ritorna fino al completamento. Al contrario, il delaycomando integrato di AppleScript gestisce gli eventi di input dell'utente mentre lo script è in pausa. (È qui che si trova il bug: se è presente l'input da tastiera dell'utente, delaycontinua l'esecuzione dello script prima che sia stata completata la durata del ritardo.)
Chris Pagina

3

Non sto dicendo che questa è la soluzione migliore, ma sembra aver risolto il mio problema. Invece di utilizzare un semplice ritardo, che viene ignorato per motivi che non capisco, sono passato a ottenere l'ora e il looping fino a quando non viene raggiunto un nuovo orario (utilizza ancora un ritardo, ma non importa se ignora il ritardo poiché lo script non continua fino al raggiungimento del tempo).

# 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

Sto ancora morendo dalla voglia di sapere perché il ritardo viene ignorato (o accelerato drammaticamente?! ??), ma questo fa il lavoro, per quanto goffo.


Il comando "ritardo" non viene "accelerato", ma viene interrotto. Durante il ritardo, si trova in un ciclo verificando se ci sono eventi di input da tastiera in modo da poter verificare il periodo di comando. Apparentemente esce erroneamente dal loop di ritardo quando viene rilevato un input dell'utente.
Chris Page

Interessante! Sto scoprendo che viene ignorato (accelerato? Interrotto?) Anche quando il mio Mac è inattivo, ma non so perché.
2oh1

Una volta che un evento di input dell'utente è nella coda degli eventi, delaycontinuerà a essere interrotto fino a quando qualcosa non gestirà gli eventi e li rimuoverà dalla coda.
Chris Page

2

Ho trovato una soluzione in un post sul forum tedesco . Aggiungi queste righe all'inizio dello script:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1

Sto riscontrando problemi nel testare la tua risposta perché, per qualsiasi motivo, il ritardo funziona attualmente come previsto sul mio Mac. Non ho idea del perché. Sto correndo il 10.10.3. Forse Apple ha corretto questo errore? O forse è solo un problema intermittente che non sta influenzando il mio Mac in questo momento. Ugh. Come ho detto sopra, tuttavia, la mia soluzione alternativa è fare in modo che Applescript ottenga l'ora corrente e poi torni all'ora corrente più x.
2oh1,

Sono in esecuzione anche 10.10.3 e vedo ancora il problema. Dal momento che non tutti vedono il problema, è probabilmente intermittente o correlato a software di terze parti o a determinate impostazioni delle preferenze. Chissà. A proposito, il tuo work-around ha probabilmente lo svantaggio che l'app continua a utilizzare il 100% del tempo della CPU durante l'attesa, mentre il corretto comportamento di ritardo è di mettere l'app in stop per quella durata, consumando così meno energia.
Thomas Tempelmann,

Sono in esecuzione 10.10.5 e questa soluzione non funziona.
Greg,

@ThomasTempelmann: il problema si verifica in presenza di input da parte dell'utente. Se non fai clic o digiti mentre lo script è in esecuzione, il bug non viene attivato.
Chris Page

Si noti che questa soluzione provoca il blocco dell'applicazione per la durata del sonno. delayelabora l'input dell'utente mentre lo script è in pausa, quindi è comunque possibile interagire con menu e finestre, ad esempio.
Chris Page

0

carzyj aveva quella che considero la migliore risposta, ma quando combinato con il metodo di Chris Page, ottieni:

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

È possibile commentare "on delay" fino a "end delay" per ripristinare il ritardo originale.


Ho anche fatto una modifica del codice simile, prima di vedere questo. Sono in esecuzione 10.10.5 e questa soluzione non funziona e blocca anche lo script per la durata del sonno.
Greg,

0

questa è una modifica alla soluzione @ chris-page

Sembra essere un equilibrio tra reattività e cattura accurata del ritardo.

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

Ma invece di dire ad Applescript di ritardare per la durata complessiva, diciamo solo di ritardare per un periodo frazionario della durata. se il periodo è inferiore a quello consentito da Apple (1/60 di secondo), impostiamolo su quel delta. Che possiamo mantenere un po 'di reattività, ma allo stesso tempo essere precisi. il sospetto è che a volte il ritardo non funzioni, quindi la ripetizione mentre il ciclo manterrà bloccato il thread, ma in scenari di successo, vogliamo che il delta di ritardo sia breve in modo che il processo possa ancora essere interrotto


Ridurre il ritardo richiesto non è necessario e può solo rallentare l'esecuzione dello script e consumare più CPU durante l'attesa. La mia versione chiama semplicemente il ritardo fino al termine dell'intera durata desiderata, consentendo delaydi ritardare il più possibile prima di continuare l'esecuzione.
Chris Page

Si noti che da quando è stata pubblicata questa risposta, ho aggiornato il mio codice da utilizzare delay endTime - (current date)anziché delay duration, il che assicura che se delay non viene interrotto non metterà in pausa lo script più del tempo richiesto originariamente, che potrebbe essere stato quello che stavi cercando di indirizzo con questa risposta.
Chris Page

0

Quindi, per mettere tutto insieme, credo che Chris significhi questo:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.