0

这是我所拥有的:

1)在“Info.plist”中包含正确的“权限”条目

  • “可编写脚本”:是
  • '脚本定义文件名':myApp.sdef

2)在类扩展“元素”标签中包含元素“元素”标签:

`<class-extension extends="application" description="The application and top-level scripting object.">
    <!-- various property tags go here -->

<element type="object item" access="r">
<cocoa key="theseObjects"/>
</element>
</class-extension>`

3)包括元素类标签:

<class name="object item" code="Objs" description="Application 'too many' object collection" plural="object items" inherits="item"> // I don't believe 'inherits' name is critical for AS to work
<cocoa class="ObjectItem"/>                     
</class>

4)包括将“NSApplication”脚本支持转发给其委托的委托方法:

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

}

5)创建一个'ObjectItem'类并将对象说明符放在那里:

 - (NSScriptObjectSpecifier *)objectSpecifier { 
NSScriptObjectSpecifier *containerRef = nil;
NSScriptObjectSpecifier *specifier = [[NSNameSpecifier alloc] initWithContainerClassDescription:[NSScriptClassDescription classDescriptionForClass:[NSApp class]] containerSpecifier:containerRef key:@"theseObjects" name:@"objectName"];
return [specifier autorelease];

6) 在应用程序的委托中发布 KVO 访问器方法:

 - (NSArray *)theseObjects;
   {
ObjectItem *thisObject = [[ObjectItem new] autorelease];
NSArray *thisArray = [NSArray arrayWithObject:thisObject];
return thisArray;
    }
}

7) 创建一个 AppleScript,它从我的元素 getter 方法返回对象:

    tell application "SpellAnalysis"
    get theseObjects
    end tell

8) 结果:错误“未定义变量对象。” “对象”中的数字 -2753

9)把我的头发拉出来

4

2 回答 2

4

关于最初的一对多帖子,作者很好地概述了到达脚本几乎可以工作的步骤。幸运的是,只需进行一些小的更改即可解决此问题:

1) 示例 AppleScript

tell application "SpellAnalysis" to get theseObjects 

不可能工作。AS 不能引用 Objective-C 变量名 ( theseObjects )。由于sdef定义了“对象项”的类和元素类型,因此必须在脚本中使用:

tell application "SpellAnalysis" to get object items -- FIX #1

2) ObjectItem 类中的对象说明符应该返回当前对象的实际名称属性值,而不是字符串@"objectName"。所以应该是:

- (NSScriptObjectSpecifier *)objectSpecifier 
{ 
    NSScriptObjectSpecifier *containerRef = nil;
    NSScriptObjectSpecifier *specifier = [[NSNameSpecifier alloc] 
        initWithContainerClassDescription:[NSScriptClassDescription classDescriptionForClass:[NSApp class]] 
        containerSpecifier:containerRef 
        key:@"theseObjects" 
        name:self.name]; // FIX #2

    return specifier;
}

3)支持上述内容的完整正确的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="SpellAnalysis Suite" code="sSIA" description="ToDo">
        <class name="object item" code="Objs" description="ToDo" plural="object items">
            <cocoa class="ObjectItem"/> <!-- KVC: Objective-C class ObjectItem : NSObject -->
            <property name="name" code="pnam" type="text" access="r" description="Its name.">
                <cocoa key="name"/>
            </property>
        </class>
        <class-extension name="SpellAnalysis application" extends="application" description="ToDo">
            <element type="object item" access="r">
                <cocoa key="theseObjects"/> <!-- KVC: app delegate's @property NSArray* theseObjects; -->
            </element>
        </class-extension>
    </suite>
</dictionary>

4)ObjectItem.h接口支持以上:

@interface ObjectItem : NSObject
    @property (nonatomic, strong) NSString *name;

    - (instancetype)initWithName:(NSString *)name;
@end

5) ObjectItem.m 文件支持以上内容:

#import "ObjectItem.h"
@implementation ObjectItem

- (instancetype)initWithName:(NSString *)name
{
    if (self = [super init])
    {
        self.name = name;
    }
    return self;
}

- (NSScriptObjectSpecifier *)objectSpecifier 
{ 
    NSScriptObjectSpecifier *containerRef = nil;
    NSScriptObjectSpecifier *specifier = [[NSNameSpecifier alloc] 
        initWithContainerClassDescription:[NSScriptClassDescription classDescriptionForClass:[NSApp class]] 
        containerSpecifier:containerRef 
        key:@"theseObjects" 
        name:self.name]; // FIX #2

    return specifier;
}
@end

6)最后,您的 App 委托类中的代码支持上述内容:

#import "MyAppDelegate.h"
#import "ObjectItem.h"

@interface MyAppDelegate ()
@property (nonatomic, strong) NSArray *theseObjects;
@end

@implementation MyAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.theseObjects = @[
        [[ObjectItem alloc] initWithName:@"Item A"],
        [[ObjectItem alloc] initWithName:@"Item B"],
        [[ObjectItem alloc] initWithName:@"Item C"]
    ];
}

- (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key
{
    if ([key isEqualToString:@"theseObjects"])
    {
        return YES;
    }
    return NO;
}
@end

就是这样,只需修复几个简单的错误(一个在脚本中,一个在对象说明符代码中),以下脚本返回预期结果:

tell application "SpellAnalysis"
    get object items -- expect a list of object references for all objects in array
end tell

--> {object item "Item A" of application "SpellAnalysis", object item "Item B" of application "SpellAnalysis", object item "Item C" of application "SpellAnalysis"}

其他脚本也可以:

tell application "SpellAnalysis"
    get object item 2 -- expect a object reference to the second item in the array
end tell

--> object item "Item B" of application "SpellAnalysis"


tell application "SpellAnalysis"
    name of object item 2 -- Expected result: the name property of 2nd obj in array
end tell

--> "Item B"
于 2014-08-23T16:30:20.227 回答
0

我想我应该发布一些关于 Cocoa Scriptability 对 Core-data 应用程序的支持的附加信息,因为那里的信息太少了。我花了至少一个月的时间试图了解如何接受这种机制。

尽管我能够使用索引说明符为我的核心数据应用程序提供 AppleScript 支持,但我发现使用“uniqueID”说明符提供了更好的匹配。更好,因为核心数据对多的关系由无序集支持,而不是数组。核心数据为您提供了一种通过对象 ID 指定托管对象的方法,该对象 ID 可以由 Cocoa Scriptability 方法评估。然而,为了使用 uniqueID 说明符实现对“太多”关系的支持,需要额外的代码元素。

1) 在“sdef”中为您将支持的每个实体提供一个属性元素。例如,为了支持我的“级别”实体,我在“级别”类标签中发布了以下内容:

<property name="id" code="ID  " type="text" access="r" description="The level's unique id. This may be a temporary id for newly-    created level objects, until they are saved.">
    <cocoa key="uniqueID"/>
</property>

请注意,该类型被指定为“文本”而不​​是“说明符”。AppleEvent 机制和 Cocoa AppleScript 支持之间的“uniqueID”交换将是一个字符串值。另请注意,“可可键”值是“唯一 ID”。AppleScript 脚本支持使用这个键('sdef' 中的典型键)来识别应用程序中符合 KVC 模式的方法名称。

2) 在包含目标对象的类中发布一个“valueInWithUniqueID”方法。正是在此方法中,您提供了一种方法来提取与传递给该方法的任何“uniqueID”相对应的托管对象。这是我在容器类“Levels”中发布的“levelsArray”KVO 方法。

- (id)valueInLevelsArrayWithUniqueID:(NSString *)uniqueID;
{
    NSManagedObject *managedObject= [[[NSApp delegate] myManagedObjectContext] objectWithID:[[[NSApp delegate] lessonsManager]    managedObjectIDForURIRepresentation:[NSURL URLWithString:uniqueID]]];
    return managedObject;
}

这是包含的“单元”类的“sdef”属性声明:

<property name="id" code="ID  " type="text" access="r" description="The unit's unique id.  This may be a temporary id for newly-created unit objects, until they are saved.">
    <cocoa key="uniqueID"/>
</property>

我的“单位”类也唤起了价值方法。请注意基本的 KVC 名称模式:

- (id)valueInUnitsArrayWithUniqueID:(NSString *)uniqueID;
{
NSManagedObject *managedObject= [[[NSApp delegate] lessonsDBase] objectWithID:[[[NSApp     delegate] lessonsManager] managedObjectIDForURIRepresentation:[NSURL   URLWithString:uniqueID]]];

    return managedObject;
}

有了这些,如果我的 AppleScript 需要从其“uniqueID”中指定一个“级别”对象,它将得到回答。当你有实体类的层次结构并且你编写一个 AppleScript 1)调用一个返回其结果的引用的命令,并且 2)使用另一个命令对该返回的结果进行操作时,这似乎开始发挥作用:

count (make new section at unit 1 of level 1)

奇怪的是,以下内容并没有唤起 value 方法:

count (unit 1 of level 1)

请注意,它缺少条件 1——缺少主要命令(例如“make”)。在这种情况下,会调用隐含的 AppleScript 'get' 命令,但 Cocoa 可脚本性似乎通过另一种方式确定实体层次结构的值。

3) 为从您支持的命令返回的所有对象提供“uniqueID”对象说明符,并为支持其隐含“get”命令的每个实体子类明确命名为“objectSpecifier”。例如,我在其“performDefaultImplementation”中发布的“克隆”命令提供以下方法:

 NSUniqueIDSpecifier *uniqueIDSpecifier = [[[NSUniqueIDSpecifier allocWithZone:[self zone]]  initWithContainerClassDescription:[NSScriptClassDescription classDescriptionForClass:[NSApp class]] containerSpecifier:sourceContainerSpecifier key:sourceKey uniqueID:uniqueID] autorelease];

根据您是使用命令操作单个对象还是一系列对象,您可以直接返回“uniqueIDSpecifier”或将其添加到最后一次添加后返回的连续此类说明符的数组中。为了支持隐含的“get”命令,您在每个托管对象实体子类中发布一个“uniqueID”对象说明符。以下说明符支持我的“单元”类子类:

- (NSScriptObjectSpecifier *)objectSpecifier {
    NSScriptObjectSpecifier *containerRef = [[NSApp delegate]levelsSpecifier];
    NSString *uniqueID = [[[self objectID] URIRepresentation] absoluteString]; // This is            the key method for determining the object's 'uniqueID'
if (uniqueID) {
    NSScriptObjectSpecifier *uniqueIDSpecifier = [[[NSUniqueIDSpecifier allocWithZone:   [self zone]]   initWithContainerClassDescription:[containerRef keyClassDescription]  containerSpecifier:containerRef key:@"unitsArray" uniqueID:uniqueID] autorelease];
   [[NSApp delegate] setUnitsSpecifier:uniqueIDSpecifier]; // Post specifier so Units  class specifier can access it
    return uniqueIDSpecifier;
   } else {
      return nil;
   }

请注意,第二条注释行表明我将此说明符的结果发布在全局变量中,以便包含类的对象说明符可以使用此说明符结果作为其容器说明符。应用程序委托是所有实体子类都可以访问应用程序范围的访问器和方法(例如此对象说明符结果)的地方。

我确实希望这可以帮助像我这样的人,上个月。

于 2013-10-25T03:02:44.780 回答