Сценарии Какао: используйте специальные типы строк, такие как необработанные данные

В моем приложении есть некоторый контент с необработанными данными, который я хочу предложить AppleScript, чтобы его можно было хотя бы просмотреть, если не обработать, сохранив его в файл или установив другой объект, который его поддерживает.

Теперь я не понимаю, какой тип данных используется для этого.

Смотрите этот вывод из редактора скриптов, например:

tell application "Script Editor"
  the clipboard as record
    --> {Unicode text:"text",
         «class BBLM»:«data BBLM6C6C756E»,
         string:"text"}
end tell

Как мне вернуть эти "данные...", которые, по-видимому, представляют собой комбинацию 4-символьных кодов и шестнадцатеричных кодированных байтов фактических данных.

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

Обновить

Похоже, это связано с реализацией scripting<type>Descriptor а также scripting<type>WithDescriptor, Я не могу найти никакой документации по этому вопросу, кроме того, что она используется в примере кода Sketch. Я предполагаю, что они будут вызваны для типа, если мне удастся определить такой пользовательский тип в моем Sdef.

Однако: я не буду знать типы, которые я хочу отправить заранее, поэтому я не могу заранее определить их в Sdef. Я больше в ситуации похожей на the clipboard: У меня есть данные в виде буфера обмена, которые я хочу вернуть, поэтому я знаю только их 4-символьные типы во время выполнения. Что означает, что меня не спросят эти обработчики. Должен быть какой-то другой способ общего создания и получения этих типов, так же, как это делает реализация буфера обмена.

3 ответа

Решение

RE: "Однако: я не буду знать типы, которые я хочу отправить заранее, поэтому я не могу заранее определить их в Sdef".

Есть способ решить эту проблему: вы можете вернуть специальную структуру списка, известную как запись пользовательского поля (typeUserField). Эта запись включает чередующиеся дескрипторы Key и Value и не требует, чтобы что-либо определялось в SDEF.

Вот элемент, который я разместил в списке рассылки АСОК в прошлом году: http://lists.apple.com/archives/applescriptobjc-dev/2015/Jan/msg00036.html

А вот код (использующий код AppleScript-ObjectiveC) для создания записи typeUserField из NSDictionary.

# ASOC implementation of - (NSAppleEventDescriptor *)scriptingRecordDescriptor for an NSDictionary
# Creates an empty record descriptor and an empty list descriptor, then
# Iterates over the dictionary and inserts descriptors for each key and each value into the list descriptor
# Finally, populates the record descriptor with the type 'usrf' and the list descriptor

on makeUserRecordDescriptor(aDict)

log aDict

set recordDescriptor to aedClass's recordDescriptor()
set listDescriptor   to aedClass's listDescriptor()

set typeUserField to 1970500198 -- 'usrf'

set itemIndex to 1 -- AS records are 1-based

repeat with aKey in aDict's allKeys()

    set aVal to aDict's valueForKey_(aKey)

    -- The values can be several different types. This code DOES NOT handle them all.

    set isStringValue  to aVal's isKindOfClass_(nssClass's |class|) = 1
    set isNumericValue to aVal's isKindOfClass_(nsnClass's |class|) = 1
    set isBooleanValue to aVal's className()'s containsString_("Boolean") = 1

    -- Insert a descriptor for the key into the list descriptor

    set anItem to aedClass's descriptorWithString_(aKey)
    listDescriptor's insertDescriptor_atIndex_(anItem, itemIndex)
    set itemIndex to itemIndex + 1

    -- Insert a descriptor (of the correct type for the value) into the list descriptor

    if isStringValue
        set anItem to aedClass's descriptorWithString_(aVal)
    else if isBooleanValue
        set anItem to aedClass's descriptorWithBoolean_(aVal's boolValue())
    else if isNumericValue
        set intValue to aVal's intValue()
        set fpValue to aVal's doubleValue()

        if intValue = fpValue
            set anItem to  aedClass's descriptorWithInt32_(aVal's intValue())
        else
            set anItem to  aedClass's descriptorWithString_(aVal's stringValue) # TODO: 'doub'
        end
    else
        set anItem to  aedClass's descriptorWithString_("Unhandled Data Type")
    end

    listDescriptor's insertDescriptor_atIndex_(anItem, itemIndex)
    set itemIndex to itemIndex + 1

end

recordDescriptor's setDescriptor_forKeyword_(listDescriptor, typeUserField)

return recordDescriptor

конец

RE: "... реализация сценарияDescriptor и сценарияWithDescriptor. Я не могу найти никакой документации по этому вопросу..."

Первое, что нужно начать, это раздел "Кодирование значения ключа и сценарии какао" в Руководстве по сценариям Какао (2008). Существует целый ряд этих методов, которые встраивают тип в имя метода. Многие из них также описаны на странице Справочника по протоколу NSScriptKeyValueCoding Фонда, но вы должны прочитать раздел "Обсуждение", чтобы найти их. Например, в:

- (id)valueWithUniqueID:(id)uniqueID inPropertyWithKey:(NSString *)key

обсуждение говорит: "Метод valueInWithUniqueID: вызывается, если он существует".

Итак, в классе Widgets вы должны реализовать valueInWidgetsWithUniqueID:

scriptingDescriptor и scriptingWithDescriptor - это специальные обработчики преобразования, которые используются, когда вы используете элемент в.sdef вашего приложения, поэтому они отображаются в Sketch для обработки типа данных typeRGBColor, списка из 3 целых чисел. Я не могу найти их и за пределами кода Sketch, но могу подтвердить, что

scriptingRGBColorDescriptor

вызывается методами в:

NSObject(NSScriptAppleEventConversion)
NSAppleEventDescriptor(NSScriptConversion)

Магия заключается в использовании NSAppleEventDescriptor, Он предлагает много инициализаторов. Это то, что в конечном итоге содержит любое значение, которое передается обратно вызывающему AppleScript (или JXA или тому, что использует механизм сценариев).

По-видимому, любое значение, возвращаемое слою сценариев Какао, например строки как NSString и числовые значения как NSNumber, в конечном итоге будет назначено объекту NSAppleEventDescriptor и преобразовано на этом шаге во внутренний формат AppleEvent.

Итак, если я хочу вернуть строку байтов, например, сохраненную в объекте NSData, все, что мне нужно сделать, это из моего метода свойства:

-(id)returnSomeBytes {
    return [NSAppleEventDescriptor descriptorWithDescriptorType:'Raw ', myNSDataObject];
}

Это закончится в AppleScript как «data Raw ...»,

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

Обратное работает так же хорошо - любые такие необработанные данные передаются в мой код как NSAppleEventDescriptor, который затем я могу соответствующим образом декодировать.

Другие вопросы по тегам