2013-08-17 30 views
0

這是我有:如何支持應用程序(NSApp)類的AppleScript元素(一對多關係)?

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)創建從我的元件getter方法返回的對象一個AppleScript:

tell application "SpellAnalysis" 
    get theseObjects 
    end tell 

8)其結果是: 錯誤「變量對象未定義。「從「物」

9)號-2753拉我的頭髮

回答

0

我想我應該張貼對核心數據的應用程序腳本化可可支持一些附加信息,因爲有那麼一點信息在那裏。我花了至少一個月的時間試圖瞭解如何接受這一機制。

雖然我能夠使用索引說明符爲我的核心數據應用程序提供AppleScript支持,但我發現使用'uniqueID'說明符提供了更好的適應性。更好的是,因爲核心數據對多關係由無序集支持,而不是數組。核心數據爲您提供了一種方法,可以通過可由Cocoa Scriptability方法評估的對象ID指定管理對象。儘管如此,爲了使用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'交換將是一個字符串值。還要注意'可可鍵'的值是'uniqueID'。該鍵('sdef'中的這些鍵的典型值)由AppleScript腳本支持使用,以在您的應用程序中標識符合KVC模式的方法名稱。

2)在包含目標對象的類中發佈'valueInWithUniqueID'方法。在此方法中,您提供了一種方法來提取與傳遞給方法的任何'uniqueID'相對應的託管對象。這裏是我的'levelsArray'KVO方法,發佈在我的容器類'Levels'中。

- (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」 A「級別」的對象,它會回答。這似乎在您擁有實體類的層次結構時發揮作用,並且您編寫的AppleScript可以:1)調用返回對其結果的引用的命令; 2)使用另一個命令對此返回結果執行操作:

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

奇怪的是,下文中不引起的值的方法:

count (unit 1 of level 1) 

注意,它缺乏條件1 - 主命令(例如,「使」)缺失。在這種情況下,隱含的AppleScript'get'命令被激發,但Cocoa scriptability似乎通過另一種方式來確定實體層次結構的值。 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; 
    } 

注二等註釋行表明我張貼此說明符的結果在一個全局變量,使包含的類的對象說明符可以使用此符結果作爲其容器說明符。應用程序委託是所有實體子類都可以訪問應用程序範圍訪問器和方法(如此對象說明符結果)的地方。

上個月,我確實希望這能幫助像我這樣的人。

3

關於原始的一對多文章,作者做了一個很好的概述步驟,以達到腳本差不多的作品。幸運的是,只需要一些小的改動來解決這個問題:

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)最後,在應用程序委託類的代碼,以支持上述:

#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" 
相關問題