Cocoa脚本:使用特殊字符串类型,如原始数据

时间:2016-04-03 13:25:18

标签: macos cocoa applescript cocoa-scripting

我的应用程序有一些我希望能够提供给AppleScript的原始数据内容,因此至少可以通过将其保存到文件或将其设置为支持它的其他对象来处理它。

现在,我不明白使用哪种数据类型来实现这一目标。

请参阅脚本编辑器中的此输出,例如:

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

如何返回这些«data ...»,它们显然是实际数据的4-char-code和hex-string编码字节的组合。

我尝试从我的脚本属性中返回一个包含原始字节数据的NSData对象,但这不起作用。

更新

它似乎与实施scripting<type>Descriptorscripting<type>WithDescriptor有关。除了在Sketch示例代码中使用之外,我找不到任何其他文档。我假设如果我碰巧在我的Sdef中定义了这样的自定义类型,那么这些将被调用。

但是:我不知道我想提前发送的类型,所以我无法在Sdef中预先定义它们。我更像是the clipboard的情况:我想要返回类似剪贴板的数据,所以我只在运行时知道它们的4-char类型。这意味着我不会被要求通过这些处理程序。必须有一些其他方式来一般地创建和接收这些类型,就像剪贴板实现一样。

3 个答案:

答案 0 :(得分:2)

RE:&#34; ...实施脚本&lt; Key&gt; Descriptor和脚本&lt; Key&gt; WithDescriptor。我找不到任何关于此的文件...&#34;

首先要做的是&#34; Key-Value Coding和Cocoa Scripting&#34; “可可脚本编写指南”(2008年)中的部分。这些方法中有很多将类型嵌入方法名称中。许多内容也记录在Foundation的NSScriptKeyValueCoding Protocol Reference页面中,但您必须阅读&#34;讨论&#34;找到它们的部分。例如,在:

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

讨论说:&#34;方法valueIn&lt; Key&gt; WithUniqueID:如果存在则被调用。&#34;

因此,在Widgets类中,您将实现valueInWidgetsWithUniqueID:

脚本&lt; Key&gt;描述符和脚本&lt; Key&gt; WithDescriptor是在您的应用程序的.sdef中使用元素时使用的特殊转换处理程序,这就是它们在Sketch中显示以处理typeRGBColor数据类型的原因,3个整数的列表。我也无法在Sketch代码之外找到这些文档,但我可以确认

scriptingRGBColorDescriptor

由以下方法调用:

NSObject(NSScriptAppleEventConversion)
NSAppleEventDescriptor(NSScriptConversion)

答案 1 :(得分:1)

RE:“但是:我不会事先知道我想要发送的类型,因此我无法在Sdef中预先定义它们。”

有一种方法可以解决这个问题:您可以返回一个称为用户字段记录(typeUserField)的特殊列表结构。此记录包括交替的键和值描述符,并且不需要在SDEF中定义任何内容。

这是我去年在ASOC邮件列表上发布的一个项目: http://lists.apple.com/archives/applescriptobjc-dev/2015/Jan/msg00036.html

这是代码(使用AppleScript-ObjectiveC代码)从NSDictionary构建typeUserField记录。

# 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

答案 2 :(得分:0)

神奇在于使用action_user_id。它提供了很多初始化器。它最终会保存传递回调用AppleScript(或JXA或任何使用Scripting引擎)的任何值。

显然,返回到Cocoa Scripting层的任何值(例如字符串为NSString,数值为NSNumber)最终都会分配给NSAppleEventDescriptor对象,并由该步骤转换为AppleEvent内部格式。

所以,如果我想返回一串字节,例如存储在NSData对象中,我所要做的就是使用我的属性方法:

 {
  "error": false,
  "requests": [
    {
      "name": "Dusan" // user with id 1
    },
    {
      "name": "Dusan"
    },
    {
      "name": "Jelena Radenkovic" // user with id 2
    },
    {
      "name": "Jelena Radenkovic"
    },
    {
      "name": "Stefan Dimitrijevic" // user with id 4
    },
    {
      "name": "Stefan Dimitrijevic"
    }
  ]
}

这将以Apple { "error": false, "requests": [ { "name": "Dusan" // getting only this user with id 1 because he sent request to the user with id 2 } ] } 结束。

我现在也理解为什么脚本引擎不会自动为我转换NSData:它需要一个类型代码,NSData不会继承它。

反过来也一样 - 任何这样的原始数据都作为NSAppleEventDescriptor传递给我的代码,然后我可以相应地进行解码。