Сценарии Какао: используйте специальные типы строк, такие как необработанные данные
В моем приложении есть некоторый контент с необработанными данными, который я хочу предложить 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: "... реализация сценария
Первое, что нужно начать, это раздел "Кодирование значения ключа и сценарии какао" в Руководстве по сценариям Какао (2008). Существует целый ряд этих методов, которые встраивают тип в имя метода. Многие из них также описаны на странице Справочника по протоколу NSScriptKeyValueCoding Фонда, но вы должны прочитать раздел "Обсуждение", чтобы найти их. Например, в:
- (id)valueWithUniqueID:(id)uniqueID inPropertyWithKey:(NSString *)key
обсуждение говорит: "Метод valueIn
Итак, в классе Widgets вы должны реализовать valueInWidgetsWithUniqueID:
scripting
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, который затем я могу соответствующим образом декодировать.