【问题标题】:Turn id back into a reference object in AppScript objective-c将 id 转回 AppScript Objective-c 中的引用对象
【发布时间】:2011-01-22 02:55:06
【问题描述】:

我正在编写一个使用 Objective-C-appscript (objc-appscript) 与 Mail 对话的应用程序。我想复制当前选择的邮件消息并稍后对其执行一些处理 -- 届时当前选择可能已更改。

MLApplication *mail = [[MLApplication alloc] initWithBundleID: @"com.apple.mail"];
MLReference *ref = [mail selection];
id theSelection = [[ref getItem] copy];

// Do something here, which may change the contents of ref,  
// but that's okay since I made a copy in theSelection

MLMoveCommand *cmd = [[theSelection move] to: [[mail mailboxes] byName:@"test"]];

// This command should move the selected messages to the mailbox but fails  
// because theSelection

MLReference *ref2 = nil; // Need to turn theSelection into an MLReference *
MLMoveCommand *cmd = [[ref2 move] to: [[mail mailboxes] byName:@"test"]];

我需要将 theSelection 转回 MLReference *。我确信这应该是一个简单的操作,但我是 appscript 的新手,需要一些指导。谢谢!

【问题讨论】:

  • 我不确定它是否需要成为 MLReference。相反,我认为它需要是一个 AppScript 列表对象。如何将 NSArray 对象转换为 AppScript 列表对象?

标签: objective-c macos applescript sourceforge-appscript


【解决方案1】:

您始终可以将 theSelection 转换为您想要的任何类型。您还可以使用class 方法查询它并找出它认为它是什么类型。不过,您可能不必这样做。

例如,

NSString *something = [(MLReference *)theSelection someFuncIMadeUp];

你可以在苹果文档中阅读所有关于运行时的东西(比如类方法):

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

【讨论】:

  • 我知道 theSelection 是一个 NSCFArray,但我想把它变成一个 MLReference。查看 MLReference 标头,有一个名为 referenceWithAppData:id)appData aemReference:(id)aemReference 的类方法,但我不确定我需要在那里放置哪些参数。
【解决方案2】:

您假设 Apple 事件 IPC 使用分布式对象等代理对象,但事实并非如此:它是 RPC + 查询。 (将 XPath over XML-RPC 视为一个粗略的类比。)这是一个常见的误解——Apple 自己完全无法解释它——但掌握 Apple 事件的基于查询的性质对于有效控制可编写脚本的应用程序至关重要。

不管怎样,这就是你出错的地方:

id theSelection = [[ref getItem] copy];

这一行复制了一个标识 Mail 的 selection 属性的 MLReference 对象,但作为引用基本上类似于一个实际上是无操作的 URL。

MLMoveCommand *cmd = [[theSelection move] to: [[mail mailboxes] byName:@"test"]];

这一行告诉 Mail 移动它在引用位置找到的对象。该命令可能会或可能不会起作用,具体取决于 Mail 的脚本支持的能力(某些应用程序可能能够使用单个命令操作多个对象;其他应用程序仅限于每个命令一个对象)。但即使它确实有效,它也会在发送命令时选择的任何内容上运行——这不是你想要的。

在这种情况下,正确的解决方案是使用get 命令来检索引用列表(在本例中为 MLReference 实例的 NSArray),您可以稍后对其进行迭代以依次移动每个引用的消息.幸运的是,Mail 返回的引用通过 id 来识别消息,这意味着它们应该继续指向原始消息对象,即使它们同时被移动。 (按索引和按名称引用的稳定性要差得多,因此您需要更加小心地处理使用它们的应用程序。)

例如(为清楚起见省略了错误检查):

MLApplication *mail = [MLApplication applicationWithBundleID: @"com.apple.mail"];
NSArray *messageRefs = [[mail selection] getItem];
// do other stuff here
MLReference *message;
for (message in messageRefs) {
    MLMoveCommand *cmd = [[mail move: message] to: [[mail mailboxes] byName: @"test"]];
    id result = [cmd send];
}

有关详细信息,请参阅 appscript 手册。此外,ASTranslate 是您的朋友。

【讨论】:

  • 感谢您的回复。我在纯 AppleScript 中使用过这种方法,但是向每条消息发送消息的速度与向整个消息列表发送消息的速度相比要慢得多。在我的另一个实现中,我使用 NSAppleScript 来编译一个执行“将选择复制到 theSelection”和移动操作的脚本。我认为这比使用 AppScript 更 hacky。
  • 所以,我想我可以在 AppScript 或 Scripting Bridge 中的 AppleScript 中做任何我想做的事情。不幸的是,SB 没有启用将列表移动到邮箱命令,只有将消息移动到邮箱命令。
  • 这条 AppleScript 行是否可以在 AppScript 中使用? “将选择复制到 theSelection” AppScript 中如何处理实例变量?我能找到的所有例子都没有提到它们。
  • 当给定应用程序引用作为直接参数时,AppleScript 的 copy 语句会根据 to 参数的内容向应用程序发送 getduplicate 命令。所以这是一条红鲱鱼;忽略它并在此处使用get。如果 Mail 的 move 命令接受引用列表(这非常罕见但并非未知;例如,Finder 允许这样做),那么要在 appscript 中利用这一点,请丢失 for 语句并将 move 命令更改为:[[mail move: messageRefs] to: [[mail mailboxes] byName: @"test"]].
  • “我想我可以在 AppScript 或 Scripting Bridge 的 AppleScript 中做任何我想做的事情。” - 某人,不;它试图将 AE IPC 装扮成 Cocoa/OO 导致部分功能受损和应用程序不兼容的趋势。 Appscript,是的,因为它不仅保留了 AE 语义,而且还非常努力地与 AS 进行 quirk-for-quirk 兼容。不过,Appscript 比 AS 更规范一些,所以有时 AS 会让您以多种方式表达操作,而这些方式只能在 appscript 中以一种方式编写 - 使用 copy 作为 duplicate/get 的别名就是一个例子。
猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多