Команда AppleScript «delay» не работает, так как переключение на Yosemite

10

Примечание: проблема с delayбыла исправлена ​​в OS X 10.11 El Capitan.

С тех пор как я перешел на Yosemite, приложения, использующие задержки, перестали работать. Как я могу это исправить?

Вот самый простой в мире Applescript, для простого примера:

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

Это должно занять 30 секунд, чтобы завершить. Если я запускаю его в Script Editor (ранее Applescript Editor), это займет 30 секунд. Но если я сохраню этот сценарий как приложение, при запуске приложения задержки будут проигнорированы, и приложение завершится за долю секунды.

Как я могу заставить Applescript отложить на указанное количество времени, прежде чем перейти к следующему шагу? Это глюк Йосемити? Есть ли надежный обходной путь?

2oh1
источник
Это работает, как и ожидалось, на моем Mac (10.10.1)
markhunte
Любая идея, что заставляет это не работать на моем? Для пояснения: он работает в редакторе сценариев, но если я сохраню сценарий как приложение, а затем запущу приложение, задержки игнорируются. Это самая странная вещь.
2h1
У меня такая же проблема на 10.10.3
Томас Темпельманн
Сообщено в Apple: openradar.me/21588747
Томас Темпельманн
1
Эта проблема была исправлена ​​в OS X 10.11 El Capitan.
Крис Пейдж

Ответы:

7

Примечание: проблема с delayбыла исправлена ​​в OS X 10.11 El Capitan.

@ 2oh1, у вас есть правильная основная идея в вашем ответе, но вот полный и правильный ответ:

Единственный разумный способ обойти это состоит в том, чтобы вызвать «задержку» в цикле, которая обеспечивает желаемую продолжительность, прежде чем продолжить. Лучший способ сделать это - переопределить «задержку» с помощью специального обработчика:

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

Это позволяет вам оставить остальную часть вашего сценария без изменений, и вы можете использовать «задержку» как обычно, например,

delay 5
display alert "I like cake!"

[ПРИМЕЧАНИЕ. Обычно пользовательский обработчик использует «длительность задержки продолжения» для вызова встроенной «задержки», но я обнаружил, что, хотя это работает в редакторе сценариев, он возвращает ошибку при использовании в апплете («Can»). t продолжить задержку. (-1708) »). Я обошел эту проблему, напрямую попросив AppleScript обработать команду задержки, вместо того чтобы использовать «продолжить».]

Проблема заключается в том, что delayпользовательский ввод обрабатывается во время паузы сценария, поэтому вы все равно можете щелкать по меню или окнам, отображаемым апплетом, и существует ошибка (исправлена ​​в 10.11), когда пользовательский ввод не вызывает delayполной продолжительности, прежде чем возобновить выполнение сценария. , Если вы не взаимодействуете с апплетом, delayработает правильно.

Крис Пейдж
источник
Является ли все это ошибкой, или есть причина, почему задержка работает таким образом с Yosemite?
2h1
Это ошибка, задержка не задерживает.
Крис Пейдж
Это так странно. Я возился с яблочным сценарием, который использует задержку прошлой ночью, и внезапно задержка снова заработала правильно. Я предположил, что ошибка была исправлена. Через час, хотя ничего не изменилось, ошибка вернулась. Я действительно сбит с толку. Это не имеет значения, хотя. Я использую переменную, чтобы установить время и задержку до пяти минут спустя (например), и она работает отлично. Итак ... проблема решена, но это не объясняет, почему проблема существует. Интересно, интересно, интересно.
2h1
1
Потому что Apple, дурак. Программное обеспечение Apple гораздо менее надежно, так как они начали выпускать OS X ежегодно. Я скучаю по более высоким второстепенным версиям OS X (например, 10.6.8), где операционная система была надежной. Вы просто не получаете такого опыта больше.
Уильям Т Фроггард
Интересно, если это ошибка (с которой я согласен), почему это все еще не исправлено? Кто-нибудь здесь сделал отчет радара? Не могли бы вы опубликовать свой идентификатор? (или / также опубликовать на openradar.me)
Томас Темпельманн
5

Когда я боролся с этой же проблемой, я наткнулся на этот ответ на не очень связанный вопрос и решил попробовать его, и, похоже, он мне подходит.

Просто замените delay 5на do shell script "/bin/sleep 5"и получите тот же результат.

JCobb
источник
Спасибо, что поделился! Как я уже говорил выше, я не могу проверить это, потому что, по причинам, которые не имеют смысла для меня, задержка 5 работает, как и сейчас, для меня (я только что проверил это снова минуту назад). Я понятия не имею, почему это иногда работает, а иногда не удается. Это так странно. В итоге я использовал обходной путь, где я получаю текущее время и устанавливаю его как переменную, а затем приостанавливаю сценарий до тех пор, пока время не станет переменным плюс одна минута (очевидно, с задержкой в ​​1 минуту). Это неуклюжий, но он работал безупречно в течение нескольких месяцев, тогда как простая задержка была прерывистой. Тьфу.
2h1
Я работаю 10.10.5, и это решение не работает, а также блокирует скрипт на время сна
Грег
@ Грег: Если он «блокирует скрипт» на время сна, значит, он работает. /bin/sleepожидает продолжительность сна и не возвращается, пока не завершится. Напротив, встроенная delayкоманда AppleScript обрабатывает события пользовательского ввода, пока скрипт находится в режиме паузы. (Именно в этом и заключается ошибка: если есть ввод с клавиатуры пользователя, delayвыполнение скрипта продолжается до того, как истечет время задержки.)
Chris Page
3

Я не говорю, что это лучшее решение, но, похоже, оно решило мою проблему. Вместо того, чтобы использовать простую задержку, которая игнорируется по причинам, которые я не понимаю, я переключился на получение времени и цикл до достижения нового времени (он все еще использует задержку, но не имеет значения, игнорирует ли он задержка, так как сценарий не продолжается, пока не будет достигнуто время).

# 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

Я все еще хочу знать, почему задержка игнорируется (или резко ускоряется?! ??), но это делает работу, неуклюжей.

2oh1
источник
Команда «delay» не «ускоряется», она прерывается. Во время задержки он сидит в цикле, проверяя, есть ли какие-либо события ввода с клавиатуры, чтобы он мог проверить Command-Period. По-видимому, он неправильно выходит из цикла задержки, когда обнаруживается любой пользовательский ввод.
Крис Пейдж
Интересный! Я обнаружил, что он игнорируется (ускорился? Прерван?), Даже когда мой Mac бездействует, но я не знаю почему.
2h1
Как только пользовательское событие ввода окажется в очереди событий, оно delayбудет продолжать прерываться, пока что-то не обработает события и не удалит их из очереди.
Крис Пейдж
2

Я нашел обходной путь в немецком сообщении на форуме . Добавьте эти строки в начало вашего скрипта:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1
Томас Темпельманн
источник
У меня проблемы с проверкой вашего ответа, потому что по какой-то причине задержка в настоящий момент работает на моем Mac должным образом. Понятия не имею почему. Я бегу 10.10.3. Возможно, Apple исправила эту ошибку? Или, может быть, это просто временная проблема, которая не влияет на мой Mac в данный момент. Тьфу. Как я уже сказал выше, мой обходной путь заключается в том, что Applescript получает текущее время, а затем задерживает его до текущего времени плюс x.
2h1
Я также использую 10.10.3 и все еще вижу проблему. Поскольку не все видят проблему, она, вероятно, неустойчива или связана с программным обеспечением сторонних производителей или с определенными настройками предпочтений. Кто знает. Кстати, ваш обходной путь, вероятно, имеет недостаток, заключающийся в том, что приложение продолжает использовать 100% процессорного времени во время ожидания, в то время как правильное поведение задержки заключается в переводе приложения в спящий режим на этот период, что потребляет меньше энергии.
Томас Темпельманн
Я работаю 10.10.5, и это решение не работает.
Грег
@ThomasTempelmann: проблема возникает при вводе пользователем. Если вы не нажмете или не введете текст во время работы скрипта, ошибка не сработает.
Крис Пейдж
Обратите внимание, что это решение приводит к тому, что приложение фактически останавливается на время сна. delayобрабатывает пользовательский ввод, пока скрипт находится в режиме паузы, поэтому вы можете, например, взаимодействовать с меню и окнами.
Крис Пейдж
0

у carzyj было то, что я считаю лучшим ответом, но в сочетании с методом Криса Пейджа вы получаете:

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

Вы можете закомментировать «задержка» через «окончание задержки», чтобы вернуться к первоначальной задержке.

Дикстер
источник
Я также сделал похожую модификацию кода, прежде чем увидеть это. Я бегу 10.10.5, и это решение не работает, а также блокирует скрипт на время сна.
Грег
0

это модификация решения @ chris-page

Кажется, что существует баланс между отзывчивостью и точным фиксированием задержки.

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

Но вместо того, чтобы сказать Applescript о задержке на общую продолжительность, мы просто скажем ему отложить на дробный период продолжительности. если период меньше, чем позволяет яблоко (1/60 секунды), тогда давайте просто установим его на эту дельту. Что мы можем сохранять некоторую отзывчивость, но все же быть точными. есть подозрение, что иногда задержка не работает, поэтому цикл повтора пока удерживает поток заблокированным, но в сценариях успеха мы хотим, чтобы дельта задержки была короткой, чтобы процесс все еще мог быть прерван

Greg
источник
Сокращение запрошенной задержки не является необходимым и может только заставить скрипт работать медленнее и потреблять больше ресурсов ЦП во время ожидания. Моя версия просто вызывает задержку до тех пор, пока не истечет вся желаемая продолжительность, позволяя delayзадержать столько, сколько возможно, прежде чем продолжить выполнение.
Крис Пейдж
Обратите внимание, что поскольку этот ответ был опубликован, я обновил свой код, чтобы использовать delay endTime - (current date)вместо него delay duration, что гарантирует, что если delay его не прервать, он не остановит сценарий дольше, чем первоначально запрошенное время, что, возможно, и было тем, что вы пытались обратитесь с этим ответом.
Крис Пейдж
0

Итак, чтобы сложить все вместе, я считаю, что Крис означает это:

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
источник