【问题标题】:Accessing property in Cocoa AppDelegate (NSApplicationDelegate) from AppleScript从 AppleScript 访问 Cocoa AppDelegate (NSApplicationDelegate) 中的属性
【发布时间】:2016-11-04 10:51:02
【问题描述】:

我有一个用 Xcode 编写的非常基本的 Cocoa 应用程序,我正在尝试使用一个简单的 AppleScript 脚本访问我的应用程序委托的属性:

tell application "HelloWorld"
    set appDelegateProperty to property1
end tell

Cocoa Scripting Guide 中的信息看起来很简单。虽然我编写的代码似乎符合键值编码 (KVC),但我看到的错误表明并非如此。

我在AppDelegate 类中添加了一个名为property1NSString 类型的综合属性,在applicationDidFinishLaunching() 方法中将其设置为@"test"。我在我的脚本定义 (SDEF) 文件中添加了条目,以允许从 AppleScript 访问该属性。

以下是相关代码(您可以在this web page 上下载 Xcode 项目的压缩副本或浏览源代码):

Info.plist

我添加了这些键以在应用程序中启用 AppleScript 支持:

<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>OSAScriptingDefinition</key>
<string>HelloWorld.sdef</string>

AppDelegate.h

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
@property   NSString*   property1;
@end

AppDelegate.m

#import "AppDelegate.h"

@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate
@synthesize property1;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    property1 = @"test";
}
@end

HelloWorld.sdef

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
 <dictionary title="HelloWorld">
    <suite name="HelloWorld" code="HELO" description="HelloWorld scripting suite">
        <class name="application" id="HELO" code="capp" description="top-level scripting object">
            <cocoa class="NSApplication"/>
            <property name="property1" code="Hadp" description="property1" type="text" access="r">
                <cocoa key="property1"/>
            </property>
        </class>
    </suite>
 </dictionary>

当我在 Xcode 调试器中启动应用程序并在脚本编辑器中执行此 AppleScript 代码时,这是我在脚本编辑器控制台中看到的错误:

脚本编辑器控制台输出

 error "HelloWorld got an error: AppleEvent handler failed." number -10000

Xcode 调试器控制台输出

 2016-07-01 15:29:18.449 HelloWorld[90280:3166995] Command: Intrinsics.get
Direct Parameter: <NSPropertySpecifier: property1>
Receivers: <NSPropertySpecifier: property1>
Arguments:     {
}
 2016-07-01 15:29:18.449 HelloWorld[90280:3166995] An exception was thrown during execution of an NSScriptCommand...
 2016-07-01 15:29:18.449 HelloWorld[90280:3166995] [<NSApplication 0x620000101560> valueForUndefinedKey:]: this class is not key value coding-compliant for the key property1.
 2016-07-01 15:29:18.449 HelloWorld[90280:3166995] Result: (null)
 2016-07-01 15:29:18.449 HelloWorld[90280:3166995] Error: -10000 "(null)"

疑难解答说明

不知何故,我的代码实际上不符合 KVC,尽管我不确定如何或为什么。

我怀疑属性位于 应用程序委托 而不是 NSApplication 类本身这一事实可能存在问题,但我可能错了。

我已经设置了绑定调试日志级别,如 Cocoa Bindings Programming Topics 文档的“Troubleshooting Cocoa Bindings”部分所示,以对绑定进行故障排除:

defaults write net.none.HelloWorld NSBindingDebugLogLevel 1

我还将脚本调试日志级别设置为 1,如 Cocoa 脚本指南的“打开脚本调试输出”部分所示,以查看更详细的调试输出,如下所示:

defaults write net.none.HelloWorld NSScriptingDebugLogLevel 1

最后,我已按照 Cocoa 脚本指南的“检查应用程序中的脚本信息”部分中的说明输出 Cocoa 从 SDEF 中提取的脚本信息的描述。这是调试器控制台命令及其输出:

po [NSClassFromString(@"NSScriptSuiteRegistry") sharedScriptSuiteRegistry]

Suite: Intrinsics ('intr'), hidden: yes
    Name: "Intrinsics", description: ""
    Class: item ('cobj'), superclass: <none>, hidden: no
        Implementation class: NSObject
        Name: "item", plural name: "items", description: "A scriptable object."
        Attribute: classCode ('pcls'), type: type ('type'), access: read-only, hidden: no
            Name: "class", description: "The class of the object."
        Attribute: scriptingProperties ('pALL'), type: record ('reco'), access: read-write, hidden: no
            Name: "properties", description: "All of the object's properties."
        Default subcontainer: <none>
        Supported command: delete, method: -
        Supported command: exists, method: -
        Supported command: set, method: -
        Supported command: get, method: -
        Supported command: count, method: -
        Supported command: move, method: -
        Supported command: duplicate, method: -
        Primitive type: <none>
    Command: get ('core'/'getd'), hidden: no
        Implementation class: NSGetCommand
        Name: "get", description: "Returns the value of the specified object(s)."
        Unnamed argument ('----'), type: specifier ('obj '), optional: no
            (No user-readable name or description needed for unnamed arguments)
        Result type: any ('****')
            Description: <none>
    Command: set ('core'/'setd'), hidden: no
        Implementation class: NSSetCommand
        Name: "set", description: "Sets the value of the specified object(s)."
        Unnamed argument ('----'), type: specifier ('obj '), optional: no
            (No user-readable name or description needed for unnamed arguments)
        Argument: Value ('data'), type: any ('****'), optional: no, hidden: no
            Name: "to", description: "The new value."
        Result type: <none> ('null')
            Description: <none>
    Value type: any ('****')
        Implementation class: NSAppleEventDescriptor
    Value type: boolean ('bool')
        Implementation class: NSNumber
    Value type: date ('ldt ')
        Implementation class: NSDate
    Value type: file ('file')
        Implementation class: NSURL
    Value type: integer ('long')
        Implementation class: NSNumber
    Value type: location specifier ('insl')
        Implementation class: NSPositionalSpecifier
    Value type: missing value ('msng')
        Implementation class: NSNull
    Value type: number ('nmbr')
        Implementation class: NSNumber
    Value type: point ('QDpt')
        Implementation class: NSData
    Value type: real ('doub')
        Implementation class: NSNumber
    Value type: record ('reco')
        Implementation class: NSDictionary
    Value type: rectangle ('qdrt')
        Implementation class: NSData
    Value type: specifier ('obj ')
        Implementation class: NSScriptObjectSpecifier
    Value type: text ('ctxt')
        Implementation class: NSString
    Value type: type ('type')
        Implementation class: NSNumber
    Object type: item ('cobj')

 Suite: HelloWorld ('HELO'), hidden: no
    Name: "HelloWorld", description: "HelloWorld scripting suite"
    Class: application ('capp'), superclass: item, hidden: no
        Implementation class: NSApplication
        Name: "application", plural name: "applications", description: "top-level scripting object"
        Attribute: property1 ('Hadp'), type: text ('ctxt'), access: read-only, hidden: no
            Name: "property1", description: "property1"
        Default subcontainer: <none>
        Primitive type: <none>
    Object type: application ('capp')

有什么想法吗?

【问题讨论】:

  • 注意:我注意到一个有点相关的问题here,但它不使用合成属性,并且似乎与我的问题略有不同。

标签: xcode macos cocoa applescript kvc


【解决方案1】:

如果密钥在AppDelegate 你必须实现

- (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key
{
    return [key isEqualToString:@"property1"]; 
}

对于多个键,声明一个包含所有键的 NSSet 属性 keySet 并返回

return [keySet containsObject:key]; 

您无需在 sdef 文件中指定 cocoa key property1,因为名称与选择器匹配。

【讨论】:

  • 谢谢!添加delegateHandlesKey() 方法就可以了。
  • 注意:我尝试在 SDEF 中评论 &lt;property name="property1"...&gt; 部分,但这导致了错误:HelloWorld got an error: Can’t get property1。所以我认为你仍然需要脚本定义文件中定义的属性。
  • 当然你需要属性本身,而不是cocoa key 行。抱歉,我的笔记有误导性。
  • 啊,我明白了。你说得对。很抱歉造成混乱,再次感谢您的帮助。 :)
  • @vadian 为什么delegateHandlesKey的文档说:“不要实现这个方法。”?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多