2

This is a question about implementing a scriptable application using Cocoa Scripting.

My app's scriptable application object contains elements of a custom class, let call it flower.

In the .sdef file, the Cocoa class for flower is specified as ScriptableFlower.

In Applescript, one can now write:

tell app "myapp"
  get flowers
end tell

My code provides an accessor function for retrieving flowers: -(NSArray*)flowers.

Now, I like to implement a way to add new flowers, so that one can write:

tell app "myapp"
  make new flower
end tell

The default behavior for this, with the default Core suite handler for "make" using NSCreateCommand, is as follows:

The scripting engine will fetch the current array of flowers by calling my flowers function, then instantiate a new Cocoa object of class ScriptableFlower, and then call setFlowers:(NSArray*) with an array that contains my original objects plus the newly created one.

However, this is not good for my application: I cannot allow the scripting engine to create objects of my scriptable classes at will.

Instead, I need to be the one instantiating them.

A half-way solution would be to implement the default -(id)init method and then detect if it's called by me - if not, I can take the extra steps. But that's not clean. I rather do not let the scripting engine create new objects at all but rather provide them myself as I may have the object "somewhere" already prepared.

Is there some provision in Cocoa Scripting that leads to it calling me whenever it wants me to create a new scriptable object?

Update

To clarify: The Cocoa Scripting docs explains that one can implement special insertion handlers (insertObject:in<Key>AtIndex:)so that one doesn't have to take the entire NSArray, but that still leads to the scripting engine to create the object. I need to be asked to create the object instead, though.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149

2 Answers2

2

The file NSObjectScripting.h provides a function for this:

- (id)newScriptingObjectOfClass:(Class)objectClass forValueForKey:(NSString *)key withContentsValue:(id)contentsValue properties:(NSDictionary *)properties;

It's available since OS X 10.5 and documented as follow:

Create a new instance of a scriptable class to be inserted into the relationship identified by the key, set the contentsValue and properties of it, and return it. Or return nil for failure. The contentsValue and properties are derived from the "with contents" and "with properties" parameters of a Make command. The contentsValue may be nil. When this method is invoked by Cocoa neither the contentsValue nor the properties will have yet been coerced using scripting key-value coding's -coerceValue:forKey: method. In .sdef-declared scriptability the types of the passed-in objects reliably match the relevant .sdef declarations however.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
1

One option is to subclass NSCreateCommand and implement your own logic.

vadian
  • 274,689
  • 30
  • 353
  • 361