Объектные спецификаторы

Объектный спецификатор определяет местоположение scriptable объекта в иерархии вместимости приложения. Сценарии какао используют объектные спецификаторы, чтобы найти объекты в Вашем приложении при выполнении команды сценария и возвратить требуемую информацию сценарием. В этой главе описываются, как Какао, пишущее сценарий использования, возражает спецификаторам и как Ваше приложение обеспечивает объектные спецификаторы для своих scriptable объектов.

Обзор объектных спецификаторов

Сценарий AppleScript содержит операторы, управляющие объектами в объектной модели AppleScript приложения. Часть оператора сценария, идентифицирующего объект, такой как fourth word, вызывается ссылкой. Ссылка редко происходит в изоляции. Обычно оператор сценария состоит из серии ссылок, которым предшествует команда и обычно подключенных друг к другу in или of, такой как get the fourth word in the third paragraph of document "Quarterly Report".

Событие Apple инкапсулирует работу, указанную оператором сценария, и поставляет ее приложению. Для событий Apple, соответствующих командам, определенным в sdef файле приложения, сценарии Какао преобразовывают событие Apple в команду сценария, содержащую всю информацию, необходимую для выполнения работы.

Для описания объектов, указанных ссылкой, команда использует объектные спецификаторы. Где оператор сценария идентифицирует объект в объектной модели AppleScript, объектный спецификатор идентифицирует соответствующий объект в самом приложении. Когда приложение должно возвратить объект сценарию выполнения вызова, Какао, пишущее сценарий также, использует объектный спецификатор, предоставленный Вашим приложением, для идентификации объекта.

Существует не всегда взаимно-однозначное соответствие между объектами AppleScript и объектами в реализации Вашего приложения. Например, a character объект в сценарии не имеет соответствия character объект в приложении.

Объектные спецификаторы и KVC

Сценарии какао полагаются на кодирование значения ключа (KVC) при оценке объектных спецификаторов. Когда приложение сначала должно работать с scriptability информацией, Какао, пишущее сценарий информации о загрузках от sdef файла приложения в глобальный экземпляр NSScriptSuiteRegistry. В то время это регистрирует описания класса для Ваших scriptable классов. В результате Какао и Ваше приложение могут получить информацию об описании класса сценария, включая ключи, о scriptable классах для использования с объектными спецификаторами.

Для получения дополнительной информации посмотрите Загрузку информация о Scriptability.

Когда реализовать объектный метод спецификатора

Любой класс в Вашем приложении, которое является частью иерархии вместимости для Вашей поддержки scriptability, наиболее вероятно потребует объектного метода спецификатора. Когда оператор сценария предназначается для Вашего приложения, приложение, возможно, должно возвратить ответ. Например, результат a get команда часто является объектом или списком объектов. Когда Какао возвращает эти объекты в событии Apple ответа, оно не возвращает указатели на объекты Objective C, оно возвращает объектные спецификаторы, определяющие местоположение scriptable объектов в иерархии вместимости. Как часть создания этих спецификаторов, Какао обращается к Вашим scriptable объектам предоставить спецификаторы для себя.

Вы обеспечиваете объектный спецификатор для scriptable класса путем реализации objectSpecifier метод. Тот метод определяется в NSScriptObjectSpecifiers (отметьте запаздывание «s»), категория на NSObject это реализует просто возвращающуюся версию nil.

Об объектных классах спецификатора

objectSpecifier метод возвращает экземпляр одного из классов, перечисленных в Таблице 6-1, которые являются подклассами NSScriptObjectSpecifier. Классы такой как NSNameSpecifier и NSUniqueIDSpecifier представляйте стандартные ссылочные формы AppleScript, таким образом, Вы не должны должны быть разделять их на подклассы. Вы выбираете лучшую версию для объекта, который необходимо указать — см. Инструкции по Интерфейсу Сценариев для руководства. Например, если объект имеет уникальное имя или уникальный идентификатор, используйте соответствующий тип спецификатора. Для безымянного объекта без ID, такого как прямоугольник или абзац текста, можно хотеть возвратить индексный спецификатор.

Большинство подклассов NSScriptObjectSpecifier имейте определенный инициализатор, который необходимо использовать.

Большинство методов инициализатора для объектного класса спецификатора включает следующие параметры:

  • (NSScriptClassDescription *)classDescription

    Здесь Вы предоставляете описание класса для контейнерного класса указанного объекта. Необходимо всегда предоставлять описание класса для спецификатора.

    Если у Вас уже есть объектный спецификатор для контейнера, можно получить описание класса для того контейнерного объекта с помощью NSScriptObjectSpecifier метод keyClassDescription, как показано в Перечислении 6-1.

    Когда можно получить класс контейнерного объекта (например, путем вызова [NSApp class]), можно использовать classDescriptionForClass метод для определения контейнерного описания, как показано в Перечислении 6-2. Если у Вас есть экземпляр класса контейнера, можно вместо этого использовать NSObject метод экземпляра classDescription получить контейнерное описание.

  • (NSScriptObjectSpecifier *)specifier

    Здесь Вы предоставляете объектный спецификатор для родительского контейнера указанного объекта. Вы обычно получаете его путем вызова objectSpecifier метод содержания объекта.

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

  • (NSString *)key

    Здесь Вы предоставляете ключ, говорящий родительский контейнер, как найти указанный объект. Ключ, который Вы передаете, основывается на информации, предоставленной в Вашем sdef файле. Например, Эскиз определяет "graphics" ключ для идентификации графического массива в документе Эскиза. (Эскиз фактически определяет исключительное "graphic" как элемент document класс, но сценарии Какао применяет свои стандартные правила, описанный в Обеспечивают Ключи для Кодирования Значения ключа, для преобразования этого ключа в строку "graphics".)

Для аннотируемого примера objectSpecifier метод, посмотрите Объектный Метод Спецификатора для Прямоугольника в Эскизе.

Более внимательное рассмотрение в объектном спецификаторе

Рассмотрите схему объектной модели и иерархии вместимости для примера приложения Эскиза, показанного на рисунке 6-1. Левая сторона этой иллюстрации показывает scriptable объекты Эскиза, правая сторона соответствующая иерархия вместимости приложения. Для оператора сценария, идентифицирующего a rectangle возразите слева, сценарии Какао предоставляют объектный спецификатор, определяющий местоположение прямоугольника и его содержания документа в иерархии вместимости справа.

  Объектная модель Эскиза рисунка 6-1 и иерархия вместимости пересмотрены
Sketch containment hierarchy revisited

Каждый объектный спецификатор содержит ссылку на свое содержание объекта, позволяющего объектным спецификаторам представлять объекты, которые могут быть глубоко вложены в иерархии объектов. Наиболее удаленный контейнер, представленный нулевым спецификатором объекта, обычно application объект, несмотря на то, что это может быть объектный спецификатор, вовлеченный в a whose пункт (NSWhoseSpecifier) или контейнер для оценки диапазона.

Рисунок 6-2 показывает спецификаторы вложенного объекта для оператора first rectangle in document "SketchDocOne":

  Спецификаторы Вложенного объекта рисунка 6-2 для прямоугольника Эскиза
Object specifiers that identify the first rectangle

Вот то, как интерпретировать информацию в этом числе:

  1. Индексный спецификатор указывает первый прямоугольник, который является объектом класса SKTRectangle. Спецификатор имеет эти компоненты:

    • Индекс для указанного объекта, в этом примере имеющего значение 0.

      Это - основанный на нуле индекс указанного прямоугольника в его содержании массива. Поскольку графические массивы Эскиза могут содержать другие виды графики, индекс для первого прямоугольника будет не всегда иметь значение 0— например, если бы предшествуется четырьмя круговой графикой, индекс имел бы значение 4.

    • Ключ, указывающий набор для указанного объекта, в этом примере имеющего значение "graphics".

      Графический массив является набором для индексируемого объекта. Ключ соответствует информацию, предоставленную Вашим sdef и сделанную доступный в запущенном приложении, как описано в Объектных Спецификаторах и KVC.

    • Контейнерная ссылка, указывающая родителя для этого объектного спецификатора. В этом примере контейнер является объектным спецификатором для документа "SketchDocOne".

  2. Спецификатор имени указывает документ, содержащий первый прямоугольник, который является объектом класса SKTDrawDocument. Спецификатор имеет эти компоненты:

    • Имя для указанного объекта, в этом примере имеющего значение "SketchDocOne".

    • Ключ, указывающий набор для указанного объекта, в этом примере имеющего значение "orderedDocuments".

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

    • Контейнерная ссылка, указывающая родителя для этого объектного спецификатора. В этом примере ссылка nil, указание, что массив документов содержится application объект.

    Оператор сценария, и таким образом объектный спецификатор, могут указать объекты, в настоящее время не существующие в приложении, вызывая состояние ошибки, когда выполняется сценарий. Например, указанный документ может не существовать, или он может не содержать указанную диаграмму. Код в классе команды должен проверить на и быть подготовлен обработать условия распространенной ошибки. (Проверку не считают подходящей для методов получателя KVC и методов установщика.)

Оценка вложенных спецификаторов

Когда сценарии Какао подготавливают команду сценария к сценарию, содержащему ссылку, они преобразовывают ссылку во вложенную серию объектных спецификаторов, таких как те показанные на рисунке 6-2. Это упаковывает эти спецификаторы вложенного объекта как получатель команды (или в некоторых случаях как параметр команды). Когда команда выполняется, приложение оценивает объектные спецификаторы в своем собственном контексте для обнаружения указанных объектов.

Оценка запускается со спецификатора верхнего уровня и продолжает вниз цепочку объектных спецификаторов, оценивая и разрешая каждого, пока не определяются идентификационные данные заключительного, вложенного дочернего объекта. Этот объект является получателем (или получателями) команды или одного из параметров команды. Кодирование значения ключа используется в качестве стандартного механизма для оценки. Объектный спецификатор запрашивает свой оцененный контейнер для значения ключа, связанного с объектным спецификатором.

Оценка объектных спецификаторов описана более подробно в Командах Сценария и Объектных Спецификаторах.

Классы спецификатора объекта какао

AppleScript распознает много типов ссылок. Для стандартных ссылочных форм Какао определяет подклассы абстрактного класса NSScriptObjectSpecifier. Эти классы показаны в Таблице 6-1. Каждый из этих объектных классов спецификатора имеет дело с идентификацией объектов в наборах (NSArray объекты).

Эти классы необычны в этом, они обеспечивают один из нескольких примеров, где Ваше приложение обычно создает экземпляры сценариев классов, определенных Какао. Вы делаете это в объектных методах спецификатора для Ваших scriptable классов. Для получения дополнительной информации об этих и связанных классах см. также Таблицу 9-2.

Таблица 6-1  ссылка AppleScript формируется и соответствующие объектные классы спецификатора

Ссылочные формы

Класс какао

Описание

Произвольный

NSRandomSpecifier

Указывает произвольный объект в наборе.

Пример: any word, some document

Фильтр

NSWhoseSpecifier

Указывает каждый объект в определенном контейнере, соответствующем указанные условия, определенные булевым выражением.

Пример: words whose color is blue или document whose name is "Letter to Santa Claus"

ID

NSUniqueIDSpecifier

Указывает объект в наборе уникальным идентификатором.

Пример: window id 739

Индекс

NSIndexSpecifier

Указывает объект в наборе индексом.

Примеры: word 5, front document

Середина

NSMiddleSpecifier

Указывает средний объект в наборе.

Пример: middle word of paragraph 2

Имя

NSNameSpecifier

Указывает объект в наборе по имени. См. документацию класса для механизма оценки.

Пример: window named "Report"

Свойство,

Каждый

NSPropertySpecifier

Указывает атрибут (свойство) или отношение объекта.

Пример: color (Свойство), every graphic of the front document (Каждый)

Диапазон

NSRangeSpecifier

Указывает диапазон объектов в наборе.

Пример: words 5 through 10

Относительный

NSRelativeSpecifier

Указывает позицию объекта в связи с другим объектом.

Пример: before word 5

Маловероятно, что необходимо будет разделить любой на подклассы из этих классов, поскольку они уже покрывают стандартный набор допустимых ссылочных форм AppleScript. Однако, если действительно необходимо создать подкласс, необходимо переопределить примитивный метод indicesOfObjectsByEvaluatingWithContainer:count: возвратить индексы элементам в контейнере, значения которого являются соответствующими ключу дочернего спецификатора. Кроме того, Вы, возможно, должны объявить любые специальные переменные экземпляра и реализовать инициализатор, вызывающий определяемый инициализатор его суперкласса, initWithContainerClassDescription:containerSpecifier:key:, и инициализирует эти переменные.

В дополнение к конкретным подклассам NSScriptObjectSpecifier показанный в Таблице 6-1, Какао обеспечивает другие классы, помогающие классам объектного спецификатора в оценке. Экземпляры этих классов помогают указать относительную позицию и представлять Булевы и логические выражения, в которые вовлечены объектные спецификаторы.

Оператор сценария может также содержать ссылки фильтра, идентифицирующие объекты в контейнерах на основе условий, указанных в булевых выражениях. Эти выражения могут быть соединены логическими операторами (AND, OR, НЕ) и возвратить надлежащее true или false значение. Ссылки фильтра начинаются со слов whose или where, как в get words where color is blue or color is red и rectangles whose x position is greater than 45. Эти ссылки могут содержать фразы такой как is, is equal to или is greater than, а также их символьные эквиваленты (такой как = и >).

Экземпляры NSWhoseSpecifier класс представляет ссылочные формы фильтра в Какао. Эти экземпляры содержат «тестовую» переменную экземпляра, которая является NSScriptWhoseTest объект.

Для получения информации об этих и связанных классах посмотрите Объектные Спецификаторы, Логические Тесты и Связанные Категории.

Реализация объектного метода спецификатора

Следующие разделы обеспечивают примеры того, как реализовать объектный спецификатор, определенный NSScriptObjectSpecifiers.

Объектный метод спецификатора для прямоугольника в эскизе

Перечисление 6-1 показывает, как пример приложения Эскиза (доступный от Apple) реализует objectSpecifier метод для SKTGraphic класс.

Перечисление 6-1  объектный метод спецификатора для прямоугольника

- (NSScriptObjectSpecifier *)objectSpecifier{
    NSArray *graphics = [[self document] graphics];// 1
    unsigned index = [graphics indexOfObjectIdenticalTo:self];// 2
    if (index != NSNotFound) {
       NSScriptObjectSpecifier *containerRef = [[self document] objectSpecifier];// 3
        return [[[NSIndexSpecifier allocWithZone:[self zone]]
            initWithContainerClassDescription:[containerRef keyClassDescription]
            containerSpecifier:containerRef key:@"graphics" index:index] autorelease];// 4
    } else {
        return nil;// 5
    }
}

Вот описание того, как этот метод обеспечивает объектный спецификатор для графического объекта. Возвращенный спецификатор состоит из индексного спецификатора для диаграммы в ее контейнере и контейнерного спецификатора для документа, содержащего массив графики:

  1. Из его документа это получает массив графики и определяет индекс графического получения, если это содержится в массиве.

  2. Это получает объектный спецификатор документа, содержащего диаграмму.

    Эскиз определяет SKTDrawDocument класс как подкласс NSDocument. Объектный метод спецификатора для NSDocument возвращает экземпляр NSNameSpecifier это идентифицирует документ по имени в массиве приложения упорядоченных документов.

  3. Это создает и инициализирует индексный спецификатор (тип NSIndexSpecifier) для графического получения и возвраты это.

    Спецификатор определяет местоположение диаграммы индексом в графике в ее документе. Несмотря на то, что сценарий AppleScript просит индексируемые элементы, как будто они на основе одни, этот индексный спецификатор, определяющий местоположение объектов в массиве, соответствующих указанным элементам, работам с основанными на нуле значениями. Для получения информации о других параметрах займитесь Объектными Классами Спецификатора.

Указание объекта приложения как контейнер

Для указания объекта приложения как контейнер верхнего уровня для спецификатора можно использовать код как следующий. Этот отрывок является частью класса документа и получает объектный спецификатор для документа по имени (а не индексом, который может стать недопустимым если документ, упорядочив изменения):

Перечисление 6-2  , Указывающее приложение как контейнер

NSScriptClassDescription *containerClassDesc = (NSScriptClassDescription *)
    [NSScriptClassDescription classDescriptionForClass:[NSApp class]];// 1
return [[[NSNameSpecifier alloc]
    initWithContainerClassDescription:containerClassDesc
    containerSpecifier:nil key:@"orderedDocuments"
    name:[self lastComponentOfFileName]] autorelease];// 2

Вот описание того, что делает этот фрагмент кода:

  1. Приложение является контейнером для списка упорядоченных документов, таким образом, этот код сначала получает описание класса из глобального объекта приложения, NSApp. (Вы никогда не передаете nil для описания класса.)

  2. Это тогда создает и возвращает автовыпущенный объектный спецификатор типа NSNameSpecifier, передача nil для containerSpecifier параметр для указания контейнера верхнего уровня, приложения. (Это - единственный случай, в котором можно передать nil для контейнера.)

    Это вызывает NSDocument метод lastComponentOfFileName получить имя документа и использования это для построения объекта спецификатора имени.

Реализация метода для оценки объектных спецификаторов

Контейнерные классы, хотящие оценить определенные объектные спецификаторы самостоятельно, должны реализовать indicesOfObjectsByEvaluatingObjectSpecifier: метод, определенный NSScriptObjectSpecifiers (категория на NSObject). Например, Вы могли бы принять решение реализовать этот метод при нахождении этого whose оценка пункта является слишком медленной, и Вы хотите сделать свою собственную оценку для ускорения ее (хотя для большинства приложений, производительности значения по умолчанию whose механизм должен быть достаточным).

Если возвращается этот метод nil, объектный метод спецификатора для класса делает свою собственную оценку. Если этот метод возвращает массив, объектный спецификатор использует NSNumber объекты в массиве как индексы указанных объектов.

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

Приложение Эскиза реализует этот метод в своем классе документа, как показано в Перечислении 6-3. Это позволяет Эскизу непосредственно обрабатывать некоторый диапазон и относительные спецификаторы для графики, таким образом, это может поддерживать операторы сценария такой как graphics from circle 3 to circle 5, circles from graphic 1 to graphic 10, или circle before rectangle 3.

Перечисление 6-3  indicesOfObjectsByEvaluatingObjectSpecifier: метод из Эскиза

- (NSArray *)indicesOfObjectsByEvaluatingObjectSpecifier:(NSScriptObjectSpecifier *)specifier {
    if ([specifier isKindOfClass:[NSRangeSpecifier class]]) {// 1
        return [self indicesOfObjectsByEvaluatingRangeSpecifier:(NSRangeSpecifier *)specifier];
    } else if ([specifier isKindOfClass:[NSRelativeSpecifier class]]) {// 2
        return [self indicesOfObjectsByEvaluatingRelativeSpecifier:(NSRelativeSpecifier *)specifier];
    }
    return nil;// 3
}

Вот описание того, как работает этот метод:

  1. Если переданный спецификатор является спецификатором диапазона, он возвращает результат вызова другого метода Эскиза для оценки спецификатора.

    Метод indicesOfObjectsByEvaluatingRangeSpecifier: позволяет более гибким спецификаторам диапазона использоваться с различными графическими ключами a SKTDrawDocument.

    Можно исследовать этот метод в Эскизе. Описание его полностью выходит за рамки этого обсуждения.

  2. Если переданный спецификатор является относительным спецификатором, он возвращает результат вызова другого метода Эскиза для оценки спецификатора.

    Метод indicesOfObjectsByEvaluatingRelativeSpecifier: позволяет более гибким относительным спецификаторам использоваться.

    Снова, этот метод доступен в Эскизе, но выходит за рамки этого обсуждения.

  3. Для любого другого типа спецификатора, этот метод возвраты nil так, чтобы объектная оценка спецификатора по умолчанию имела место.

Неявно указанные подконтейнеры

Сценарии какао предоставляют поддержку для неявно указанных подконтейнеров. Неявно указанный подконтейнер является контейнером объекта, который может быть указан в сценарии AppleScript контекстом, а не прямой ссылкой. Без этой функции сценарий должен был бы полностью указать путь к слову в, например, документ TextEdit:

fourth word of text of front document

Можно сделать жизнь проще для сценаристов, использующих приложение путем избавления их от необходимости писать полные ссылки на объекты в ситуациях, где может быть безопасно принята часть ссылки. Например, следующее было бы более простым, но разумным способом относиться к тому же слову, так как текст является очевидным контейнером слов в документе:

fourth word of front document

Т.е. можно позволить of text быть неявно указанным контекстом, вместо явно указанного в сценарии.

Для поддержки неявно указанного подконтейнера Вы добавляете a contents элемент к class элемент для содержания класса в Вашем sdef файле. contents элемент указывает, что сценарист может получить содержание объекта этого типа класса, не указывая контейнер, содержащий содержание.

Например, предположите, что Ваше приложение имеет класс документа, MyTextDocument, это обрабатывает текст с экземпляром NSTextStorage класс. NSTextStorage поддержки scriptability для слов, абзацев и других текстовых элементов перечислены в Таблице 3-2.

Ваше приложение может превратить текстовый экземпляр ресурса хранения в неявно указанный подконтейнер, так, чтобы пользователь не должен был указывать его в сценарии, но мог указать просто документ, как в выборке, показанной выше. Для этого Вы добавляете a contents запись для document класс поддержки, как показано в Перечислении 6-4. Это contents элемент указывает это для сценария для доступа к связанному с текстом содержанию a document объект, это может просто указать document объект, не имея необходимость указывать контейнер в объекте.

MyTextDocument класс реализовал бы средства доступа, соответствующие ключ Cocoa, определенный в sdef: т.е. contents и setContents:. Для идеи того, на что могли бы быть похожими эти средства доступа, посмотрите столь же именованные средства доступа для класса текстовой области (SKTTextArea) в приложении Эскиза.

  Определение класса перечисления 6-4 для текстового документа, содержа элемент содержания

        <class name="document" code="docu"
                description="A text document.">
            <cocoa class="MyTextDocument"/>
            <contents name="text contents" code="TeCo" type="rich text"
                description="The text of the document.">
                <cocoa key="contents"/>
            </contents>
        </class>

Когда Вы предоставляете a contents запись, надлежащее NSPropertySpecifier когда ссылка с помощью того контейнерного класса иначе была бы недопустима, будет вставлен в объектную цепочку включения спецификатора.