AppleScript 很酷。我可以在普通的 Objective-C 中做同样的事情吗?

发布于 2024-10-06 19:40:48 字数 501 浏览 3 评论 0 原文

所以我正在开发我的小 Mac 应用程序,我想用它来控制 Adium。 AppleScript 非常酷:

tell application "Adium"
    go away with message "Zoned in for Maths."
end tell

(如果您想知道这应该是什么。为了真正开始学习,我需要创建将更改我的 IM 状态的应用程序,当然......)

我在脚本编辑器中尝试过,它有效,而且我很确定从 Cocoa 应用程序调用 AppleScript 会很简单。

但。

AppleScript 是唯一的方法吗?我不介意使用 AppleScript,但它看起来像是菜鸟编程。

有没有什么方法可以在没有 AppleScript 的情况下以普通 Objective-C 的方式做与上面代码相​​同的事情?

有人会向我指出相关文档吗?我尝试过谷歌,但好像我什至不知道我在寻找什么。

谢谢!

so I'm working on my little Mac app, and I want control Adium with it. AppleScript is very cool:

tell application "Adium"
    go away with message "Zoned in for Maths."
end tell

(If you're wondering what this is supposed to be. In order to actually start studying I need to create application that will change my IM status, of course ... )

I tried it in Script Editor, it worked, and I'm pretty sure that calling AppleScript from Cocoa application is gonna be trivial.

But.

Is AppleScript the only way? I don't mind using AppleScript, but it looks like programming for noobs.

Is there any way to do the same thing as above code does without AppleScript, in plain Objective-C somehow?

Would someone point me to relevant documentation? I tried Google but it was like I don't even know what I'm looking for.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蒲公英的约定 2024-10-13 19:40:48

Mac OS X 中的进程间通信是通过 Apple Events 来完成的。 AppleScript 是向其他应用程序发送和接收 Apple 事件的一种方法。

因此,您只需要直接构建 Apple 事件并将其从 Objective-C 或任何其他语言发送到其他应用程序。

老实说,如果您只是想更改 Adium 的状态,最简单的方法是使用 NSAppleScript 并从 Objective-C 内部传递您刚刚编写的内容。

如果您想做更复杂的事情,脚本Bridge 是必经之路。该机制将 Apple Events 的对象层次结构映射到 Objective-C 的对象层次结构。

如果您认为这仍然是新手的方式,您应该通过 NSAppleEventDescriptor

好吧,我们中的一些老手认为使用 Objective-C 是一种娘娘腔的方式。如果您这么认为,您应该直接处理称为 AEDesc 等的 C 结构。请参阅 Apple 事件编程指南相应的参考

不过,我认为使用 OS X 的人都是菜鸟。真正的人使用Linux。

我爸爸会说使用 GUI 的人太被宠坏了。

重点是,你不必关心这是否是新手的方式。重要的是你能否达到你想要的目标。事实上,AppleScript 是一种非常强大的动态语言,但很多人并没有充分认识到它的强大。阅读 AppleScript 语言指南并了解惊讶。

Interprocess communication in Mac OS X is done by something called Apple Events. AppleScript is one way to send and receive Apple Events to other applications.

Therefore, you just need to construct Apple Events directly and send it to the other app, from Objective-C or whatever other language.

Honestly, if you just want to change the status of Adium, it's easiest to use NSAppleScript and pass what you just wrote, from inside Objective-C.

If you want to do more complicated stuff, Scripting Bridge is the way to go. This mechanism maps Apple Events' object hierarchy to Objective-C's object hierarchy.

If you think that's still a newbie's way, you should directly create Apple Events via NSAppleEventDescriptor.

Well, some of us old timers think using Objective-C is a sissy's way. If you think so, you should directly deal with C structs called AEDesc and such. See Apple Events programming guide and the corresponding reference.

However, I think people who use OS X are all noobs. Real people use Linux.

My dad would say people who use GUI are just too spoiled.

The point is, you don't have to care whether it is a newbie's way or not. The important thing is whether you can achieve what you want. In fact, AppleScript is a very powerful, dynamical language, whose power is not well appreciated by many people. Read AppleScript language guide and be surprised.

指尖上得阳光 2024-10-13 19:40:48

最简单的方法是使用 NSAppleScript

NSAppleScript *script = [[NSAppleScript alloc] 
    initWithSource:@"tell application \"Adium\" to go away with message \"Zoned in for Maths.\""
];

要获得更强大的访问脚本的方式,请使用 脚本桥。 Scripting Bridge 至少需要 10.5 SDK。您首先需要准备您的应用程序。

  1. 使用 sdefsdp 命令行实用程序为您想要控制的应用程序生成头文件(请参阅“准备编写代码" 了解详细信息)。
  2. 将生成的标头添加到您的项目中。
  3. 将 ScriptingBridge 框架添加到您的项目中。之后,您可以使用 Objective-C 调用来控制其他应用程序。

之后,您可以使用 Objective-C 向应用程序发送脚本命令。

AdiumApplication *adium = [SBApplication applicationWithBundleIdentifier:@"com.adiumX.adiumX"];
for (AdiumAccount* acct in [adium accounts]) {
    [acct goAwayWithMessage:(AdiumRichText *)@"Zoned in for Maths."];
}

状态消息是 Adium 的富文本类型(底层是 NSTextStorage),但它可以从纯文本转换,因此传递 NSString 而不是真正的 AdiumRichText< /code> 应该可以正常工作。

有几个圈子需要跳过。例如,您不能 直接使用其 ObjC 类在目标应用程序中创建脚本对象;您必须使用 classForScriptingClass: 获取类,然后您可以使用该类正常创建对象(即 allocinit< /code>, initWithProperties &c.)。

// creating an AdiumContactGroup
NSDictionary *props = [NSDictionary 
    dictionaryWithObjectsAndKeys:
        @"mathies",@"name",
        nil
];
AdiumContactGroup *mathies= [[[[adium classForScriptingClass:@"contact group"] alloc] 
                              initWithProperties:props]
                             autorelease];
if (mathies) {
    [[adium contactGroups] addObject:mathies];
}

请注意,其他语言(例如 Python 和 Ruby)也具有脚本绑定。

The simplest way would be to use NSAppleScript

NSAppleScript *script = [[NSAppleScript alloc] 
    initWithSource:@"tell application \"Adium\" to go away with message \"Zoned in for Maths.\""
];

For a more powerful way of accessing scripting, use Scripting Bridge. Scripting Bridge requires at least the 10.5 SDK. You first need to prepare your app.

  1. Use the sdef and sdp command line utilities to generating header files for the applications you wish to control (see "Preparing to Code" for details).
  2. Add the generated header to your project.
  3. Add the ScriptingBridge framework to your project. After that, you can use Objective-C calls to control the other application.

After that, you can use Objective-C to send scripting commands to the application.

AdiumApplication *adium = [SBApplication applicationWithBundleIdentifier:@"com.adiumX.adiumX"];
for (AdiumAccount* acct in [adium accounts]) {
    [acct goAwayWithMessage:(AdiumRichText *)@"Zoned in for Maths."];
}

Status messages are Adium's rich text type (which is NSTextStorage under the hood), but it's convertable from plain text, so passing an NSString rather than a true AdiumRichText should work fine.

There are a few hoops to jump through. For example, you can't create scripting objects in the target application by using its ObjC classes directly; you must use classForScriptingClass: to get the class, which you can then use to create objects as normal (i.e. alloc and init, initWithProperties &c.).

// creating an AdiumContactGroup
NSDictionary *props = [NSDictionary 
    dictionaryWithObjectsAndKeys:
        @"mathies",@"name",
        nil
];
AdiumContactGroup *mathies= [[[[adium classForScriptingClass:@"contact group"] alloc] 
                              initWithProperties:props]
                             autorelease];
if (mathies) {
    [[adium contactGroups] addObject:mathies];
}

Note that other languages (such as Python and Ruby) also have Scripting bindings.

弥枳 2024-10-13 19:40:48

其他人提到发送完整的 Applescript 或使用脚本桥。第三种选择是使用 Appscript,它也适用于 Python 和 Ruby。在某些方面,它比使用脚本桥更干净(IMO)。而且绝对更容易。尽管在其他方面 Scripting Bridge 更好。它还具有名为 ASTranslate 的应用程序的优势,该应用程序会将大多数 Applescript 调用转换为 Appscript。这是您的小 Applescript 示例的 Appscript。

ADApplication *adium = [ADApplication applicationWithName: @"Adium"];
ADGoAwayCommand *cmd = [[adium goAway] withMessage: @"Zoned in for Maths."];
id result = [cmd send];

Others have mentioned sending full Applescript or using the Scripting Bridge. A third choice is to use Appscript which is also available for Python and Ruby. It is a little cleaner (IMO) than using the Scripting Bridge in some ways. And definitely easier. Although in other ways Scripting Bridge is better. It also has the advantage of an application called ASTranslate which will translate most Applescript calls into Appscript. Here's the Appscript for your little Applescript example.

ADApplication *adium = [ADApplication applicationWithName: @"Adium"];
ADGoAwayCommand *cmd = [[adium goAway] withMessage: @"Zoned in for Maths."];
id result = [cmd send];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文