Can't get Apple SimpleScripting example to work when using NSApplicationDelegate

I am trying to write a trivial Objective-C application: I just want the application to display a word in the status bar and allow the word to be updated via AppleScript. To be honest, I don't know much about AppleScript and nothing about Objective-C. But it can't be that hard, because it only took me 2 hours to get a menu bar that has menu items and responds to basic AppleScript commands like "quit", so I'm 95% as good as it is there is. Unfortunately, I spent the next 6 hours figuring out a way to provide this application with a simple property that I can get and set via AppleScript.

Here is my .h code:

#import <Cocoa/Cocoa.h>

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

      

The method foobaz

is the one I used to try and make a readable property ( *window

is part of the template I gave to Xcode and was not relevant to the problem). Here is my .sdef file:

<?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>

      

So, I set it up the same as Apple's SimpleScripting example: https://developer.apple.com/library/mac/#samplecode/SimpleScripting/Introduction/Intro.html

However, I tried to run this in a script editor:

tell application "StautsMenuApp"
    properties
end tell

      

And I just get a list of the main properties without being mentioned foobaz

, unlike Apple's example where the custom property appears next to the main properties when it is run.

I feel like I've tried a hundred variations and read a hundred examples, but can't get anything to work. Any help is appreciated.

+3


source to share


2 answers


There are many problems with your SDEF file.

  • While this is not a major issue, when defining your own "types" ( OSType

    codes), all lowercase letters are historically reserved for Apple. So, you should be able to do something like 'Smas'

    or 'Smas'

    , but not 'Smas'

    .

  • It might have been a typo in the web browser, but you got it wrong inhereits

    on the line <class name="application" code="smaa" inhereits="application"...

    . It is important that the spelling is correct so that you can "extend" the base AppleScript class application

    with your own custom properties. This may be the reason why you only see the default application properties in the AppleScript editor. (While just fixing the spelling might work, there are other fixes you should make.)

  • You are trying to point out that the Cocoa class is for your extended application

    AppleScript class AppDelegate

    , but this is problematic because it AppDelegate

    does not inherit from NSApplication

    as shown in the Apple.sdef example, rather it inherits from plain old NSObject

    .

Before moving on to how I will rewrite SDEF, I will consider that the basic idea is how the Apple SDEF example works to add custom properties application

to the default AppleScript class . The AppleScript application

class corresponds to the NSApplication

Cocoa class . When you launch an application, OS X creates an instance NSApplication

(or a subclass of it, as specified in the NSPrincipalClass

application's Info.plist entry ). This instance manages the application. There are two possible ways in Cocoa to add additional AppleScript properties to an existing class NSApplication

: 1) create a custom subclass NSApplication

that contains additional properties, or 2) use the Objective-C category to extend the existing classNSApplication

as-is. (In Cocoa, the Objective-C categories are a way to add additional functionality to an existing class without the potential complexity that subclasses introduce.) Apple's example SimpleScripting

uses the latter approach (Objective-C categories) to add additional functionality.

Below I will discuss how to rewrite 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>

      

You will notice that I indicated that I am creating my own AppleScript class application

that inherits from the standard AppleScript class application

. I pointed out that the Cocoa class for this custom application

is NSApplication

. I added a custom AppleScript property whose name foobaz

and type text

. (The AppleScript class text

will correspond to the Cocoa class NSString

). Also important is that I have specified that the Cocoa key is to access this custom property foobaz

. This Cocoa key specifies the name of the Objective-C method that will be used to provide the property value. The configuration defined above indicates that a custom property foobaz

can be retrieved by calling a method foobaz

on a shared object instance NSApplication

.

To implement this on the Cocoa side, I defined the category (MDScriptingAdditions)

on NSApplication

as shown below:

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

      

You can see that I am basically redirecting the processing of these methods to the class AppDelegate

you would like to customize.

AppDelegate.h:

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    IBOutlet NSWindow                    *window;
    IBOutlet NSTextField                *foobazTextField;

    NSString                            *foobaz;
}
- (NSString *)foobaz;
- (void)setFoobaz:(NSString *)aFoobaz;
@end

      

This setting allows you to get and set a custom property foobaz

via AppleScript. When you set a value, the value displayed in the text box foobaz:

will change to the value shown in the figure below:

enter image description here

Sample project: SimpleScriptingAppDelegate.zip

+2


source


The only thing I can see is the problem in your sdef. The code for this line should be "capp". This standard and it will be the same in any sdef file. It is defined by Apple, so you need it.

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

      



After that, you will have access to this method like this ...

tell application "StautsMenuApp" to foobaz

      

0


source







All Articles