Macos Cocoa脚本:使用特殊的字符串类型,如原始数据
我的应用程序有一些原始数据内容,我希望能够提供给AppleScript,这样它至少可以被查看,即使不需要将其保存到文件或设置为支持它的其他对象 现在,我不知道使用哪种数据类型来实现这一点 查看脚本编辑器的输出,例如:Macos Cocoa脚本:使用特殊的字符串类型,如原始数据,macos,cocoa,applescript,cocoa-scripting,Macos,Cocoa,Applescript,Cocoa Scripting,我的应用程序有一些原始数据内容,我希望能够提供给AppleScript,这样它至少可以被查看,即使不需要将其保存到文件或设置为支持它的其他对象 现在,我不知道使用哪种数据类型来实现这一点 查看脚本编辑器的输出,例如: tell application "Script Editor" the clipboard as record --> {Unicode text:"text", «class BBLM»:«data BBLM6C6C756E»,
tell application "Script Editor"
the clipboard as record
--> {Unicode text:"text",
«class BBLM»:«data BBLM6C6C756E»,
string:"text"}
end tell
如何返回这些«数据…»,它们显然是实际数据的4字符编码和十六进制字符串编码字节的组合
我尝试从脚本属性返回包含原始字节数据的NSData对象,但这不起作用
更新
它似乎与实现scriptingDescriptor
和scriptingWithDescriptor
有关。除了在草图示例代码中使用之外,我找不到任何关于此的文档。如果我碰巧在Sdef中定义了这样一个自定义类型,我假设将为该类型调用这些
但是:我不知道要提前发送的类型,因此无法在Sdef中预先定义它们。我的情况更类似于剪贴板:我想返回类似剪贴板的数据,所以在运行时我只知道它们的4字符类型。这就意味着我不会被要求通过这些处理程序。必须有其他方法来创建和接收这些类型,与剪贴板实现的方法相同。神奇之处在于使用
NSAppleEventDescriptor
。它提供了许多初始值设定项。它最终保存了传递回调用AppleScript(或JXA或任何使用脚本引擎的东西)的任何值
显然,任何返回到Cocoa脚本层的值,例如字符串NSString和数值NSNumber,最终都会被分配给NSAppleEventDescriptor对象,并通过该步骤转换为AppleeEvent内部格式
因此,如果我想返回一个字节字符串,例如存储在NSData对象中,我所要做的就是从我的property方法返回:
-(id)returnSomeBytes {
return [NSAppleEventDescriptor descriptorWithDescriptorType:'Raw ', myNSDataObject];
}
这将在AppleScript中以«数据原始…»
结束
我现在也明白了为什么脚本引擎不会为我自动转换NSData:它需要一个类型代码,而NSData不会继承它
反之亦然——任何此类原始数据都会作为NSAppleEventDescriptor传递到我的代码中,然后我可以对其进行相应的解码。RE:“…实现scriptingDescriptor和scriptingWithDescriptor。我找不到任何有关此的文档…”
首先要开始的是《Cocoa脚本编写指南》(2008)中的“键值编码和Cocoa脚本编写”部分。有许多方法将类型嵌入到方法名称中。基金会的NSScriptKeyValueCoding协议参考页中也记录了许多,但您必须阅读“讨论”部分才能找到它们。例如,在:
- (id)valueWithUniqueID:(id)uniqueID inPropertyWithKey:(NSString *)key
讨论中说:“如果方法valueInWithUniqueID:存在,将调用它。”
因此,在Widgets类中,您将实现valueInWidgetsWithUniqueID:
scriptingDescriptor和scriptingWithDescriptor是在应用程序的.sdef中使用元素时使用的特殊转换处理程序,这就是为什么它们显示在草图中以处理typeRGBColor数据类型,即3个整数的列表。我也无法在草图代码之外找到这些文档,但我可以确认这一点
scriptingRGBColorDescriptor
由中的方法调用:
NSObject(NSScriptAppleEventConversion)
NSAppleEventDescriptor(NSScriptConversion)
RE:“但是:我不知道要提前发送的类型,因此我无法在Sdef中预先定义它们。”
有一种方法可以解决这个问题:您可以返回一个特殊的列表结构,称为用户字段记录(typeUserField)。该记录包括交替键和值描述符,不需要在SDEF中定义任何内容
这是我去年在ASOC邮件列表上发布的一个项目:
下面是从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
end
NSData
对象用于符合NSCoding
的自定义值类型
,这些值类型不能由AppleScript支持的基本类表示。例如,基本的AppleScript类型point
和rectangle
是用NSData
包装的C类型。要定义自定义的值类型
,您必须在sdef文件中提供目标类,并在目标类的一个类别中实现脚本…
方法。在根据您在我的另一个问题()中的评论进行进一步挖掘后,我终于明白了您的意思,但我还没有理解,也就是说,这一切都归结为使用NSAppleEventDescriptor,这是每个Cocoa类型在将值返回到正在运行的Applescript之前最终被分配到的类型。确切地说,Cocoa脚本可能是一件很棒的事情,但文档记录很差,而且很容易出错。在瑞士这里,我们会说“s'isch en saich”(类似于“屁股痛”),所以,感谢你的帮助,没有你的指点,我还没有弄明白这一点,尽管现在一切都是如此“当然,这完全有道理!”:)我希望这也能帮助其他人。对于那些像以前一样使用Cocoa层的人来说,这可能都是显而易见的东西,但我完全被难住了。我的测试表明,即使你没有实现scriptingWithDescriptor
函数,您将通过valueWithUniqueID:
处理程序获得原始的NSAppleEventDescriptor
,然后您可以从中提取数据和描述符类型。一旦在Sdef中为属性指定了特定类型,就有必要实现scriptingDescriptor
。如果使用“any”作为类型,则不需要这样做。这似乎证实了它们是作为描述符强制过程的一部分被调用的。当您指定“any”类型时,您就是