使用NSApplicationDelegate时,无法使Apple的SimpleScripting示例正常工作

时间:2013-02-17 21:12:56

标签: cocoa properties applescript sdef nsapplication-delegate

我正在尝试编写一个简单的Objective-C应用程序:我只想要一个应用程序,它将在状态栏中显示一个单词,并允许通过AppleScript更新单词。说实话,我对AppleScript知之甚少,对Objective-C一无所知。但是,它不是那么难,因为它只花了我2个小时来获得一个菜单项的菜单栏应用程序,并响应核心AppleScript命令,如“退出”,所以我95%的方式。不幸的是,我花了接下来的6个小时尝试找到一些方法来为这个应用程序提供一个我可以通过AppleScript获取和设置的简单属性。

这是我的.h代码:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    NSWindow *window;
    IBOutlet NSMenu *statusMenu;
    NSStatusItem *statusItem;
}
@property (assign) IBOutlet NSWindow *window;
- (NSString*) foobaz;
@end

foobaz方法是我用来尝试创建可读属性的方法(*window是我通过XCode给出的样板文件的一部分,与手头的问题无关)。这是我的.sdef文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
  <xi:include
    href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef"
    xpointer="xpointer(/dictionary/suite)"/>
  <suite name="StatusMenuApp suite" code="smas"
    description="StatusMenuApp specific classes.">
    <class name="application" code="smaa" inhereits="application"
      description="Application object.">
      <cocoa class="AppDelegate"/>
      <property name="foobaz" code="smas" type="text" access="r"/>
    </class>
  </suite>
</dictionary>

所以我设置它就像Apple的SimpleScripting示例一样:https://developer.apple.com/library/mac/#samplecode/SimpleScripting/Introduction/Intro.html

但是,我尝试在脚本编辑器中运行它:

tell application "StautsMenuApp"
    properties
end tell

我只是得到一个核心属性的列表,没有提及foobaz,不像Apple的例子,当我运行它时,自定义属性与核心属性一起出现。

我觉得我已经尝试了一百种变化,并阅读了一百个例子,但无法获得任何工作。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:2)

您的SDEF文件存在许多问题。

  1. 虽然这不是一个主要问题,但在定义自己的“类型”(OSType代码)时,所有小写字母在历史上都是为Apple保留的。因此,您应该执行类似'Smas''sMas'但不是'smas'的操作。

  2. 在网络浏览器中,这可能是一个拼写错误,但您在inhereits行中拼错了<class name="application" code="smaa" inhereits="application"...。拼写正确非常重要,这样您就可以使用自己的附加属性正确“扩展”基础AppleScript application类。这可能是您只在AppleScript编辑器中看到默认应用程序属性的原因。 (虽然单独纠正拼写可能会让事情发生变化,但您还应该做出其他更正。)

  3. 您正在尝试指定“扩展”application AppleScript类的Cocoa类为AppDelegate,但这是有问题的,因为AppDelegate不会继承自NSApplication {1}}类似于Apple的示例.sdef中指定的,而是继承自普通的NSObject

  4. 在继续讨论如何重新编写SDEF之前,我将回顾一下Apple的示例SDEF如何将自定义属性添加到默认的AppleScript application类背后的基本思想。 AppleScript application类对应于NSApplication Cocoa类。当您启动应用程序时,OS X会创建一个NSApplication实例(或其子类,由应用程序的Info.plist文件中的NSPrincipalClass条目指定)。此实例管理应用程序。在Cocoa中,有两种方法可以将其他AppleScript属性添加到现有NSApplication类:1)创建包含其他属性的NSApplication自定义子类,或者2)使用Objective-C类别按原样扩展现有的NSApplication类。 (在Cocoa中,Objective-C类别是一种向现有类添加附加功能的方法,而没有子类化引入的潜在复杂性)。 Apple的SimpleScripting示例使用后一种方法(Objective-C类别)来添加附加功能。

    下面是我如何重写SDEF。

    SimpleScriptingAppDelegate.sdef:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
    <dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
        <xi:include
        href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef"
        xpointer="xpointer(/dictionary/suite)"/>
        <suite name="StatusMenuApp suite" code="SSAD"
                     description="StatusMenuApp-specific classes.">
            <class name="application" code="capp" inherits="application"
                                     description="Application object.">
                <cocoa class="NSApplication"/>
                <property name="foobaz" code="Foob"
                    description="Description of the foobaz property." type="text">
                    <cocoa key="foobaz"/>
                </property>
            </class>
        </suite>
    </dictionary>
    

    您会注意到我已经指定我正在创建一个继承自标准AppleScript application类的自定义AppleScript application类。我已经指定此自定义application的Cocoa类是NSApplication。我添加了一个名为foobaz且类型为text的自定义AppleScript属性。 (AppleScript text类将对应于Cocoa NSString类。同样重要的是我已经指定访问此自定义属性的Cocoa键是foobaz。此“Cocoa键”指定将用于提供属性值的Objective-C方法的名称。上面定义的配置指定可以通过调用foobaz对象的共享实例上的foobaz方法来获取自定义NSApplication属性。

    为了在Cocoa方面实现这一点,我在(MDScriptingAdditions)上定义了NSApplication类别,如下所示:

    MDNSApplicationScriptingAdditions.h:

    @interface NSApplication (MDScriptingAdditions)
    
    - (NSString *)foobaz;
    - (void)setFoobaz:(NSString *)aFoobaz;
    
    @end
    

    MDNSApplicationScriptingAdditions.m:

    #import "MDNSApplicationScriptingAdditions.h"
    #import "AppDelegate.h"
    
    @implementation NSApplication (MDScriptingAdditions)
    
    - (NSString *)foobaz {
        return [(AppDelegate *)[NSApp delegate] foobaz];
    }
    
    - (void)setFoobaz:(NSString *)aFoobaz {
        return [(AppDelegate *)[NSApp delegate] setFoobaz:aFoobaz];
    }
    @end
    

    你可以看到我基本上将这些方法的处理转发到AppDelegate类,这就是你想要设置的方法。

    AppDelegate.h:

    @interface AppDelegate : NSObject <NSApplicationDelegate> {
        IBOutlet NSWindow                    *window;
        IBOutlet NSTextField                *foobazTextField;
    
        NSString                            *foobaz;
    }
    - (NSString *)foobaz;
    - (void)setFoobaz:(NSString *)aFoobaz;
    @end
    

    此设置允许您通过AppleScript获取和设置自定义foobaz属性。设置该值将导致foobaz:文本字段中显示的值更改为您设置的值,如下图所示:

    enter image description here

    示例项目:SimpleScriptingAppDelegate.zip

答案 1 :(得分:0)

我唯一看到的就是你的sdef中的一个问题。此行的代码需要为“capp”。这是标准的,在任何sdef文件中都是一样的。它由Apple定义,因此您需要它。

<class name="application" code="smaa" inhereits="application"
      description="Application object.">

执行此操作后,您可以像这样访问该方法......

tell application "StautsMenuApp" to foobaz