2015-07-28 2 views
1

Согласно Apple documentation on Scripting Bridge performance, мы должны стремиться использовать пакетные операции на SBElementArrays, так как звонки Apple происходят дорого.Scripting Bridge: Объединение SBElementArrays

... whenever possible you should always use one of the “batch operation” array methods instead of enumerating the array. These methods avoid the inefficiency of enumeration because they send a single Apple event rather than one Apple event per item in the array.

Я использую Scripting Bridge с приложением System Events, и я в состоянии получить пункты меню из меню успешно. Это намного быстрее, чем метод NSAppleScript, который я использовал ранее.

Что бы я хотел сделать, это объединить несколько элементов SBElementArrays, каждый из которых содержит пункты меню из разных меню. План состоит в том, чтобы затем запустить пакетную операцию один раз, а не делать это для каждого меню отдельно.

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

Первая попытка

Если я пытаюсь создать пустой элемент SBElementArray, а затем цикл по пунктам меню, добавляя каждый набор пунктов меню, например, так:

SBElementArray* menuItemCombinedArray = [[SBElementArray alloc] init]; 
for (SystemEventsMenuBarItem* menu in menuBar.menus) { 
    menuItemCombinedArray = [[menuItemCombinedArray arrayByAddingObjectsFromArray:menu.menuItems] mutableCopy]; 
} 

NSArray* menuItemNameArray = [menuItemCombinedArray arrayByApplyingSelector:@selector(name)]; 

Я получаю ошибку о том, что [SBElementArray init] should never be used, что немного нечетно, поскольку SBElementArray является подклассом NSMutableArray.

Второй попытка

Далее я попробовал дилетантский путь, где я создал SBElementArray отдельно для первого меню, а затем петельного через остальное меню и добавил тот, SBObjects один в то время, как так:

SBElementArray* menus = menuBar.menus; 
SystemEventsMenuBar* firstMenu = menus.firstObject; 
SBElementArray* menuItemCombinedArray = firstMenu.menuItems; 

[menus removeObjectAtIndex:0]; 

for (SystemEventsMenuBarItem* menu in menus) { 
    SBElementArray* tempMenuItemsArray = menu.menuItems; 
    for (int i = 0; i < tempMenuItemsArray.count; i++) { 
     [menuItemCombinedArray addObject:[tempMenuItemsArray objectAtIndex:i]]; 
    } 
} 

NSArray* menuItemNameArray = [menuItemCombinedArray arrayByApplyingSelector:@selector(name)]; 

Но теперь я получаю другую ошибку: [SBElementArray addObject:]: can't add an object that already exists.'

Резюме

Из того, что я читал в поисках, это похоже на скриптовый мост в целом, и SBElementArray, в частности, выглядят неловко. Но Scripting Bridge для меня намного быстрее, чем NSAppleScript, гораздо ближе к тому, к чему я стремился. Я думаю, что если бы я смог добиться этой оптимизации, я был бы в отличной форме.

Заранее благодарим за любую помощь!

ответ

4

SBElementArray является не массива - это много дыма-н-зеркала BS утаиваний иначе простого факт, что Apple, событие IPC является не ООП, но RPC плюс простые реляционные запросы.

Что вы действительно имеете под этим, что SBElementArray dross - это спецификатор одного объекта, который описывает отношения «один ко многим» между «объектами» в объектной модели Apple Event Object, идеализированное, виртуальное представление данных пользователя, представленных в программный пользовательский интерфейс.

Приложение также определяет различные обработчики событий Apple для выполнения операций над его AEOM - созданием, удалением, перемещением, копированием и т. Д. - идея заключается в том, что вы отправляете запрос в приложение, например.duplicate (every track whose artist is "Bjork") to (playlist "Icelandic"), а получающий обработчик точно определяет, как выполнить эту операцию для вас.

Насколько хорошо этот подход, основанный на запросах, работает на практике, зависит от того, насколько хорошо реализована поддержка AEOM приложения: часто базовый уровень модели реализует коллекции как упорядоченные массивы, а не неупорядоченные наборы, и поскольку вы в основном выполняете множество операций тип, который чаще встречается в RDBMS, так что в случае перемещения элементов массива вокруг друг друга существуют всевозможные возможности для ошибок и других ошибок. Но базовая концепция не является необоснованной (просто PITA для надежной реализации); увы, авторы SB, похоже, считают, что «реляционные графики слишком тяжелы для пользователей какао» (что, без сомнения, является большим сюрпризом для пользователей CoreData), поэтому постарайтесь скрыть все это под вонючей некомпетентной ORM.

Таким образом, нет абсолютно никакого смысла пытаться применить NS[Mutable]Array семантику к проблеме, как вы делаете, потому что SBElementArray s не являются локальным (или удаленным) массивами, но искалеченные затемненные обертки вокруг AEOM запросов. Другими словами, чтобы понять, почему то, что вы делаете, не работает и как это делается, вам нужно понять, как работает AEOM, как работает SB, как это работает, и как SB переводит свою ложь в [ очень ограниченное] поведение AEOM.

Таким образом, когда вы применяете -[SBElementArray arrayByApplyingSelector:], он фактически не выполняет итерацию массива; вместо этого он создает спецификатор объекта формы |selector name| of |elements| of... и отправляет его в приложение в случае get для решения; в результате это список значений указанных свойств. Конечно, все это оказывается совершенно бесполезным, если вы хотите выполнить что-либо другое, кроме простой операции get, например. set (rating of every track of playlist "Icelandic") to 100, потому что SB API слишком искалечен и предвзято, чтобы вы могли выразить это, хотя это абсолютно правильный запрос.

...

TL; DR: Это пустая трата времени, пытаясь сделать что-нибудь нетривиальное в SB, потому что сильнее вы нажимаете, тем больше его псевдо-OO подделка разваливается. Только [официально поддерживается] способ делать события Apple правильно через AppleScript, и, как вы говорите, используя AS через NSAppleScript, это упражнение в паховой штамповке, которое едва менее болезненно, чем SB (хотя отчасти это будет потому, что вы не сомнение в том, что это неправильно, то есть генерировать пользовательский исходный код AS посредством строковой затирки и компиляции и выполнять его на лету вместо calling parameterized handlers in precompiled .scpt files, загруженного из вашего приложения.

К счастью, 10.6 представили мост AppleScript-ObjC, который, несмотря на свои недостатки, на сегодняшний день является самым простым и быстрым способом интеграции AS и ObjC-кода, поскольку он позволяет вам определять AppleScript script objects that appear to your ObjC code almost as if they were native Cocoa classes and instances. Это было бы моим рекомендуемым подходом к вам и забыть о СБ для чего-либо, кроме тривиальных задач (или просто забыть об этом в целом и придерживаться AS, что может быть напугано, но по крайней мере в основном это понимается, менее нечестное naff).

+0

Большое спасибо за подробное объяснение. Я пытался сообщить календарю, чтобы показать определенный элемент, пока не выясню, что календарь uid и EKEventStore используют совпадение относительно самого календаря, но не для событий. По этой причине мне нужно будет найти событие по имени. Это, в свою очередь, требует много лет. Я просто отказываюсь от этого лома. –

Смежные вопросы