Polecenie „opóźnienie” AppleScript nie działa od czasu przejścia na Yosemite

10

Uwaga: problem delayzostał rozwiązany w systemie OS X 10.11 El Capitan.

Od czasu aktualizacji do Yosemite, Applescripts, które używają opóźnień przestały działać. Jak mogę to naprawić?

Oto najprostszy na świecie skrypt jabłkowy dla prostego przykładu:

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

Powinno to zająć 30 sekund. Jeśli uruchomię go w Script Editor (wcześniej Applescript Editor), wykonanie go zajmuje 30 sekund. Ale jeśli zapiszę ten skrypt jako aplikację, po uruchomieniu aplikacji opóźnienia zostaną zignorowane, a aplikacja zajmie ułamek sekundy.

Jak zmusić skrypt Apple do opóźnienia przez określony czas przed przejściem do następnego kroku? Czy to usterka Yosemite? Czy istnieje niezawodne obejście?

2oh1
źródło
Działa to zgodnie z oczekiwaniami na moim Macu (10.10.1)
markhunte
Masz pojęcie, co powoduje, że nie działa na moim? Aby wyjaśnić: działa w edytorze skryptów, ale jeśli zapiszę skrypt jako aplikację, a następnie uruchomię aplikację, opóźnienia są ignorowane. To najdziwniejsza rzecz.
2oh1
Mam ten sam problem 10.10.3
Thomas Tempelmann
Zgłoszono do Apple: openradar.me/21588747
Thomas Tempelmann
1
Ten problem został rozwiązany w systemie OS X 10.11 El Capitan.
Chris Page

Odpowiedzi:

7

Uwaga: problem delayzostał rozwiązany w systemie OS X 10.11 El Capitan.

@ 2oh1, masz właściwą podstawową ideę w swojej odpowiedzi, ale oto pełna i poprawna odpowiedź:

Jedynym rozsądnym sposobem obejścia tego problemu jest wywołanie „opóźnienia” w pętli, która zapewnia upłynięcie pożądanego czasu trwania przed kontynuowaniem. Najlepszym sposobem na to jest zastąpienie „opóźnienia” za pomocą niestandardowego modułu obsługi:

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

Umożliwia to pozostawienie pozostałej części skryptu bez zmian i można normalnie używać „opóźnienia”, np.

delay 5
display alert "I like cake!"

[UWAGA: Zwykle niestandardowy moduł obsługi używałby opcji „kontynuuj opóźnienie”, aby wywołać wbudowane „opóźnienie”, ale odkryłem, że chociaż działa to w edytorze skryptów, zwraca błąd, gdy jest używany w aplecie („Can” t kontynuuj opóźnienie. (-1708) ”). Obejrzałem ten problem, mówiąc bezpośrednio AppleScript, aby obsługiwał polecenie opóźnienia zamiast używać „kontynuuj”, aby się tam dostać.]

Problem polega na tym delay, że przetwarza dane wprowadzone przez użytkownika podczas wstrzymywania skryptu, dzięki czemu nadal możesz klikać menu lub okna wyświetlane przez aplet, i występuje błąd (naprawiony w 10.11), w wyniku którego dane wejściowe użytkownika delaynie czekają na pełny czas trwania przed wznowieniem wykonywania skryptu . Jeśli nie wchodzisz w interakcję z apletem, delaydziała poprawnie.

Chris Page
źródło
Czy to wszystko jest błędem, czy może opóźnienie działa w ten sposób z Yosemite?
2oh1
Jest to błąd, którego opóźnienie nie opóźnia.
Chris Page
To jest takie dziwne. Majstrowałem przy skrypcie jabłkowym, który wykorzystuje opóźnienie innej nocy, i nagle opóźnienie znów działało poprawnie. Zakładałem, że błąd został naprawiony. Godzinę później, mimo że nic się nie zmieniło, błąd powrócił. Jestem naprawdę zaskoczony. Nie ma to jednak znaczenia. Używam zmiennej, aby ustawić czas i opóźnienie do pięciu minut później (na przykład), i działa idealnie. Więc ... problem rozwiązany, ale to nie wyjaśnia, dlaczego problem istnieje. Ciekawe, interesujące, interesujące.
2oh1
1
Ponieważ Apple wygłupiał się. Oprogramowanie Apple jest znacznie mniej niezawodne, odkąd co roku wypuszczają system OS X. Tęsknię za mniejszymi wersjami wyższego OS X (jak 10.6.8), w których OS był niesamowicie solidny. Po prostu nie masz już takiego doświadczenia.
William T Froggard,
Zastanawiam się, czy jeśli jest to błąd (z którym się zgadzam), dlaczego nadal nie jest naprawiony? Czy ktoś tutaj zgłosił raport z radaru? Czy mógłbyś wtedy opublikować jego identyfikator? (lub / również post na openradar.me)
Thomas Tempelmann
5

Walcząc z tym samym problemem, natknąłem się na odpowiedź na niezbyt związane pytanie i postanowiłem spróbować, a wydaje mi się, że to działa.

Wystarczy wymienić delay 5się do shell script "/bin/sleep 5"i uzyskać ten sam rezultat.

JCobb
źródło
Dzięki za udostępnienie! Jak powiedziałem wcześniej, nie jestem w stanie tego przetestować, ponieważ z powodów, które nie mają dla mnie sensu, opóźnienie 5 działa teraz tak, jak powinno dla mnie (właśnie przed chwilą przetestowałem to ponownie). Nie mam pojęcia, dlaczego to czasami działa, a czasami kończy się niepowodzeniem. To jest takie dziwne. Skończyło się na obejściu, w którym otrzymuję bieżący czas i ustawiam go jako zmienną, a następnie wstrzymuję skrypt, aż czas będzie zmienny plus jedna minuta (oczywiście z 1-minutowym opóźnieniem). Jest niezgrabny, ale działa bezbłędnie przez miesiące, a proste opóźnienie jest sporadyczne. Ugh.
2oh1
Używam 10.10.5 i to rozwiązanie nie działa, a także blokuje skrypt na czas snu
Greg
@Greg: Jeśli „blokuje skrypt” na czas snu, to działa. /bin/sleepczeka na czas snu i nie powraca, dopóki się nie zakończy. Natomiast wbudowane delaypolecenie AppleScript obsługuje zdarzenia wejściowe użytkownika, gdy skrypt jest wstrzymany. (W tym tkwi błąd: jeśli wprowadzono klawiaturę użytkownika, delaykontynuuje wykonywanie skryptu przed upływem czasu opóźnienia).
Chris Page
3

Nie twierdzę, że to najlepsze rozwiązanie, ale wydaje się, że rozwiązało mój problem. Zamiast korzystać z prostego opóźnienia, które jest ignorowane z powodów, których nie rozumiem, przestawiłem się na uzyskiwanie czasu i zapętlanie się do nowego czasu (nadal używa opóźnienia, ale nie ma znaczenia, czy ignoruje opóźnienie, ponieważ skrypt nie jest kontynuowany, dopóki nie zostanie osiągnięty czas).

# 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

Nadal nie mogę się doczekać, aby wiedzieć, dlaczego opóźnienie jest ignorowane (lub gwałtownie przyspieszone?! ??), ale to sprawia, że ​​praca jest wykonywana, niezgrabna jak na razie.

2oh1
źródło
Polecenie „opóźnienie” nie jest „przyspieszane”, jest przerywane. Opóźniając, siedzi w pętli, sprawdzając, czy są jakieś zdarzenia wejściowe z klawiatury, aby mógł sprawdzić okres polecenia. Najwyraźniej niepoprawnie wychodzi z pętli opóźnienia, gdy zostanie wykryte wejście użytkownika.
Chris Page
Ciekawy! Dowiaduję się, że jest ignorowany (przyspieszony? Przerywany?), Nawet gdy mój Mac jest bezczynny, ale nie wiem dlaczego.
2oh1
Gdy zdarzenie wejściowe użytkownika znajdzie się w kolejce zdarzeń, delaybędzie kontynuowane, dopóki coś nie obsłuży zdarzeń i usunie je z kolejki.
Chris Page
2

Znalazłem obejście w niemieckim poście na forum . Dodaj następujące wiersze na początku skryptu:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1
Thomas Tempelmann
źródło
Mam problem z przetestowaniem Twojej odpowiedzi, ponieważ z jakiegokolwiek powodu opóźnienie działa na moim komputerze Mac zgodnie z oczekiwaniami. Nie mam pojęcia dlaczego. Używam 10.10.3. Być może Apple naprawiło ten błąd? A może to tylko sporadyczny problem, który nie wpływa obecnie na mój komputer Mac. Ugh. Jak już wspomniałem powyżej, moim obejściem jest to, aby Applescript pobierał bieżący czas, a następnie opóźniał się do bieżącego czasu plus x.
2oh1
Korzystam również z wersji 10.10.3 i nadal widzę problem. Ponieważ nie wszyscy widzą ten problem, prawdopodobnie jest on przerywany lub związany z oprogramowaniem innych firm lub z niektórymi ustawieniami preferencji. Kto wie. Przy okazji, obejście problemu ma prawdopodobnie tę wadę, że aplikacja zużywa 100% czasu procesora podczas oczekiwania, podczas gdy właściwym zachowaniem opóźnienia jest uśpienie aplikacji na ten czas, a tym samym zużycie energii.
Thomas Tempelmann
Używam 10.10.5 i to rozwiązanie nie działa.
Greg,
@ThomasTempelmann: Problem występuje, gdy użytkownik wprowadzi dane. Jeśli nie klikniesz ani nie wpiszesz podczas działania skryptu, błąd nie zostanie wyzwolony.
Chris Page
Zauważ, że to rozwiązanie powoduje zawieszenie się aplikacji na czas snu. delayprzetwarza dane wejściowe użytkownika, gdy skrypt jest wstrzymany, dzięki czemu można na przykład wchodzić w interakcje z menu i oknami.
Chris Page
0

carzyj miał odpowiedź, którą uważam za najlepszą, ale w połączeniu z metodą Chrisa Pagea otrzymujesz:

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

Możesz skomentować „opóźnienie” do „opóźnienie zakończenia”, aby powrócić do pierwotnego opóźnienia.

Dickster
źródło
Dokonałem również podobnej modyfikacji kodu, zanim to zobaczyłem. Używam 10.10.5 i to rozwiązanie nie działa, a także blokuje skrypt na czas snu.
Greg,
0

jest to modyfikacja rozwiązania @ chris-page

Wydaje się, że jest to równowaga między reaktywnością a dokładnym rejestrowaniem opóźnienia.

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

Ale zamiast mówić Applescriptowi, aby opóźniał cały czas trwania, po prostu mówimy mu, żeby opóźniał o ułamek czasu trwania. jeśli okres jest krótszy niż pozwala jabłko (1/60 sekundy), ustawmy go właśnie na tę różnicę. Że możemy zachować pewien czas reakcji, a jednocześnie zachować dokładność. podejrzewa się, że czasami opóźnienie nie działa, więc powtarzanie pętli while spowoduje zablokowanie wątku, ale w scenariuszach sukcesu chcemy, aby delta opóźnienia była krótka, aby proces mógł być nadal przerywany

Greg
źródło
Skrócenie żądanego opóźnienia jest niepotrzebne i może jedynie spowolnić działanie skryptu i zużywać więcej procesora podczas oczekiwania. Moja wersja po prostu wywołuje opóźnienie, aż upłynie cały pożądany czas trwania, co pozwala delayna jak największe opóźnienie, zanim będzie można kontynuować wykonywanie.
Chris Page
Zauważ, że ponieważ ta odpowiedź została opublikowana, zaktualizowałem kod, aby go używać delay endTime - (current date)zamiast delay duration, co zapewnia, że ​​jeśli delay nie zostanie przerwany, skrypt nie zatrzyma się dłużej niż pierwotnie żądany czas, który mógł być tym, co próbujesz adres z tą odpowiedzią.
Chris Page
0

Podsumowując, uważam, że Chris ma na myśli to:

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
źródło