我的应用程序有一些原始数据内容,我希望能够提供给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
有关。除了草图示例代码中使用的文档外,我找不到任何其他文档。如果我碰巧在我的Sdef中定义了这样一个自定义类型,我假设这些将被调用用于该类型。
但是:我不知道我想提前发送的类型,所以我不能在Sdef中预先定义它们。我的情况更类似于the clipboard
:我有类似剪贴板的数据要返回,所以我在运行时只知道它们的4个字符类型。这意味着我不会被这些经纪人问到。必须有其他方法来通用地创建和接收这些类型,就像剪贴板实现一样。
RE:"…正在实现脚本<Key>描述符和脚本<Key>WithDescriptor。我找不到任何有关此的文档…"
首先要开始的是《Cocoa脚本指南》(2008)中的"键值编码和Cocoa脚本"部分。有一大堆这样的方法将类型嵌入到方法名称中。基金会的NSScriptKeyValueCoding协议参考页面中也记录了许多内容,但您必须阅读"讨论"部分才能找到它们。例如,在:
- (id)valueWithUniqueID:(id)uniqueID inPropertyWithKey:(NSString *)key
讨论中说:"如果方法valueIn<Key>WithUniqueID:存在,就会调用它。"
因此,在Widgets类中,您将实现valueInWidgetsWithUniqueID:
脚本<键>描述符和脚本<键>WithDescriptor是一种特殊的转换处理程序,当您在应用程序的.sdef中使用元素时会使用它,这就是为什么它们在Sketch中显示来处理类型RGBColor数据类型,即3个整数的列表。我也找不到草图代码之外的这些文档,但我可以确认
scriptingRGBColorDescriptor
由中的方法调用
NSObject(NSScriptAppleEventConversion)
NSAppleEventDescriptor(NSScriptConversion)
RE:"但是:我不知道我想提前发送的类型,所以我不能在Sdef中预先定义它们。"
有一种方法可以解决这个问题:您可以返回一个称为用户字段记录(typeUserField)的特殊列表结构。此记录包括交替的Key和Value描述符,并且不需要在SDEF中定义任何内容。
这是我去年在ASOC邮件列表上发布的一条消息:http://lists.apple.com/archives/applescriptobjc-dev/2015/Jan/msg00036.html
下面是从NSDictionary构建typeUserField记录的代码(使用AppleScript ObjectiveC代码)。
# 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
结束
神奇之处在于使用NSAppleEventDescriptor
。它提供了很多初始化程序。它最终保存了传递回调用AppleScript(或JXA或任何使用脚本引擎的东西)的任何值。
显然,返回到Cocoa脚本层的任何值,如NSString之类的字符串和NSNumber之类的数值,最终都会被分配给NSAppleEventDescriptor对象,并通过该步骤转换为AppleEvent内部格式。
因此,如果我想返回一个字节字符串,例如存储在NSData对象中,我所要做的就是从我的属性方法
-(id)returnSomeBytes {
return [NSAppleEventDescriptor descriptorWithDescriptorType:'Raw ', myNSDataObject];
}
这将在AppleScript中以«data Raw ...»
的形式结束。
我现在也明白了为什么脚本引擎不会自动为我转换NSData:它需要一个NSData没有继承的类型代码。
反之亦然——任何这样的原始数据都会作为NSAppleEventDescriptor传递给我的代码,然后我可以相应地对其进行解码。