开发者

Turn id back into a reference object in AppScript objective-c

I'm writing an app that talks to Mail using Objective-C-appscript (objc-appscript). I want to make a copy of the currently selected mail messages and perform some processing o开发者_运维问答n it at a later -- at which time the current selection may have changed.

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"]];

I need to turn theSelection back into an MLReference *. I'm sure this should be a simple operation, but I am new to appscript and require some guidance. Thanks!


You can always cast theSelection to whatever type you want it to be. You can also query it and find out what type it thinks it is using the class method. You probably don't have to do this though.

For example,

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

You can read all about the runtime stuff (like the class method) in the apple doc:

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


You're assuming Apple event IPC uses proxy objects like Distributed Objects, but that's not the case: it's RPC + queries. (Think XPath over XML-RPC as a rough analogy.) It's a common misconception - Apple themselves totally fail at explaining it - but grasping Apple events' query-based nature is essential to controlling scriptable apps effectively.

Anyway, here's where you're going wrong:

id theSelection = [[ref getItem] copy];

This line copies an MLReference object identifying Mail's selection property, but as a reference is basically analogous to a URL that's effectively a no-op.

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

This line tells Mail to move the object(s) it finds at the referenced location. That command may or may not work depending on how capable Mail's scripting support is (some apps may be capable of manipulating multiple objects with a single command; others are limited to a single object per command). But even if it does work, it will be operating on whatever's selected at the time the command is sent - which isn't what you're after.

The correct solution in this case is to use a get command to retrieve a list of references (in this case, an NSArray of MLReference instances), which you can later iterate over to move each of the referenced messages in turn. Fortunately, the references that Mail returns identify messages by id, which means that they should continue pointing to the original message objects even if they're moved in the meantime. (By-index and by-name references are much less stable, so you need to be a lot more careful working with apps that use those.)

For example (error checking omitted for clarity):

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];
}

See the appscript manual for more information. Also, ASTranslate is your friend.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜