Adding applescript class file to Cocoa project

Hi All,

I’ve been searching for a post that mentioned adding applescript file to an existing cocoa project without luck.

Is it possible to call an applescript class method from cocoa app? I tried adding the class and connecting it to an instance in IB but can not connect to that instance. I guess the alternative is to build an ASOC app first and add all the oBJ-c files in there but it would be great to do it the other way.

Thanks, Rob

Wow, timing… I was JUST now reading this one where Shane explains it a bit, but I’m still not getting it to work just right. But, it’s at:
http://macscripter.net/viewtopic.php?id=31322

Actually, I’m looking to tie it in without IB being involved, making an Obj-C Command-Line tool. Getting errors, but I think I’m missing an alloc/init, since it’s not tied to a “blue box” in IB.

Ok, that’s the post I am looking for:

I added the framework and the lines to main:

#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>

int main(int argc, char *argv[])
{
    [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];

    return NSApplicationMain(argc, (const char **) argv);
}

I added a blue cube in IB and set its class to that of my testScript.applescript but it won’t connect to either my oBJ-c delegate or to any button. Not sure what I am doing wrong here…

Rob

I found the same thing… I followed that post exactly, with same names and everything. Being still kind of new it took me a while (and many new projects) to figure out what was what. But, I ran into what you did… Finding that things would not allow to hook up like I expected.

My problem, though, is that I haven’t done this much even without ASOC injected, so I can’t tell just at a glance what’s wrong.

Shane is pretty sharp around here, I’ve seen by browsing around, but I have a feeling that he whipped that one up without testing and ended up with just a small error.

Here’s to looking around some more. Google searching for “loadAppleScriptObjectiveCScripts” doesn’t turn up much, but any example code that’s complete will need to include that, I think.

Here’s to pressing on and trying again and again. My error count is dropping, at least. :slight_smile:

So I added an ASOC applescript to the cocoa project

script ASClass
	property parent : class "NSObject"

on displayDialog()
		display dialog "Hello world!"
end displayDialog

end script

and attached it to an instance (blue cube) in iB.

If I select “read class files” in IB and select my script, it come back with “parsed 1 class file but no classes were found.”

It just sits there dead in the water.

I’m sure I am missing something obvious.

Thanks, Rob

I don’t know what this could be!

I’m trying to solve your guy’s problem, but I get this ONE ERROR!

I’m seeing the same thing. At best, following Shane’s example code, I seem to remember getting a warning at this line:

[myASClass myTest];

… saying that myASclass may not understand the -myTest method. Maybe because there’s no @interface letting other objects know what methods our object understands?

I’m going to hit the beginner docs and start out with plain simple new ObjC objects right from the top and see if I can follow along step by step with how an AS object relates…

Ok. I found the document I was wanting. From Apple, a well written “Introduction to the Objective-C Programming Language” guide.

Which at first makes me think that we need an @interface to let other objects know what methods it understands, but then I see that we name our superclass with:


// Obj-C:
@interface myObjcClass : NSObject {
}
@end

// ASOC
script myASclass
	property parent : class "NSObject"
end script

So is this handling our @interface? I can see how an ASOC object can run a method (or handler) in our scripts without an @interface, but I’m wondering if the ASOC framework is enough to let Obj-C class know what methods our object provides without an @interface?

Pressing on with the basics…

Maybe… we make an applescript file as a .m and make a .h ourselves? I’ll try, but it sounds too crazy!

EDIT: Yeah, no hope. :frowning:

As far as I can see, you can’t call an AS handler as a class method from Objective-C. The problem happens at compile time, presumably because the compiler can’t handle AS classes – the fact that instance methods work is probably because a variable is used and the class is recognised at runtime.

(That’s it’s not a problem with class methods per se is shown by using something like “[[myASClass class] myTest]” where myASClass is an IBOutlet connected to an AS class. I guess there may be some way of referring to a class dynamically that I don’t know of.)

However, you can call AS handlers as instance methods provided you instantiate in the nib (obviously you can’t instantiate in code because that means using class methods like alloc and init). The code pointed to does that, and I just tested it here again – it does work, nothing left out.

Even with instance methods, you’ll get compiler warnings because there’s no AS equivalent of .h files. You can ignore them, but if they annoy you, you can get rid of them by defining them in a formal protocol and having one of your Objective-C classes say it implements it.

Hi Shane,

OK now I at least got a button to trigger the applescript method in ASClass.

As soon as I get the ASClass instantiated in IB I do get warnings on build and run:

NSAutoreleaseNoPool(): Object 0x100111c10 of class NSPathStore2 autoreleased with no pool in place - just leaking

Is that what you were referring to, that could be ignored? “just leaking” sounds a bit ominous.

What I can’t quite get is the outlet in my delegate so I can call the [[myASClass class] myTest]

What would the type of IBOutlet be? The applescript class is ASClass. “@class ASClass” isn’t recognized as a class.

#import <Cocoa/Cocoa.h>

@class BDController;

@interface ObjprojaAppDelegate : NSObject <NSApplicationDelegate> {
    NSWindow *window;
	IBOutlet BDController* Bcontroller;
	IBOutlet NSTextField* textFeild3;
	
}

@property (assign) IBOutlet NSWindow *window;

@end

Rob

That warning sounds like you don’t have garbage collection turned on.

Here’s my test code:

#import <Cocoa/Cocoa.h>

@class SomeAppAppDelegate;

@interface ObjCClass : NSObject {

	IBOutlet SomeAppAppDelegate *myASClass;
} 

-(IBAction)doStuff:(id)sender;
-(IBAction)doStuffClass:(id)sender;

@end

And the .m file:

#import "ObjCClass.h"

@implementation ObjCClass

-(IBAction)doStuff:(id)sender {
    [myASClass myTest];
}

-(IBAction)doStuffClass:(id)sender {
    [[myASClass class] myTest];	
}

@end

Got it! Don’t know why it didn’t work the first few times around. does now.

Yes Garbage collection was off. I am learning obj-c and memory management, finally gaining a foothold there. I suppose it is mandatory to turn GC on if using ASOC applescript classes?

Thanks Shane.

Rob

No – but you’ll have to include all the retain()s and release()s if you don’t.

Hi Shane,

That’s what I thought, but just including the script without calling any methods seems to trigger the warning. I commented out the code and still get “autoreleased with no pool in place - just leaking.” What is getting autoreleased?

script ASClass
	property parent : class "NSObject"
	
	(*on callDialog_(sender)
		display dialog "Hello world"
	end callDialog_
	
	on displayDialog()
		display dialog "Hello world"
	end displayDialog*)
	
end script

Rob

I don’t know, and I don’t know that I want to know :slight_smile:

Could it be the “[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts]” in main.m?

I do and I don’t.

Cheers, Rob

Indeed, in a non-GC environment every Cocoa call in main.m must be wrapped with an autorelease pool

[code]#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>

int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
[pool release];
return NSApplicationMain(argc, (const char **) argv);
}[/code]

Is your test using both an ObjCClass.h and ObjCClass.m ??? That’s what I had set up:

Well, I got mine to work finally, but I had to make a change to…

Which I thought looked funny at first, and seemed to react the wrong way (from what I expected) in IB.

From a bit of experience in pure ASOC, this is telling me that any messages I want to send to an instance of ASClass are actually going to be sent to SomeAppAppDelegate, since “myASClass” is tied to it with “IBOutlet SomeAppAppDelegate *myASClass;”. Thus the error messages I was getting:

I looked your code over and over and over and thought it seemed wrong, but you had indicated that it works, so I figured I was just not understanding some message passing voodoo when working in real ObjC.

So when I see:

This tells me that I’m wanting to invoke the “myTest” method on SomeAppAppDelegate. That seems to match error in the log. So I changed the IBOutlet and fixed broken connections in IB:

Now I’m getting my messages (method calls) properly in ASClass. Whew. As I expand on that and run more tests I find something interesting. I get warning messages on 3 of these 4 methods:

I understand you said we can ignore them, but I find it interesting that it thinks one with an arg is valid, but not one without. Haven’t tested multiple args yet.

Back to expanding tests.

Another thing to note: You can set up an “on init()” method in your ASClass to set some values on instance variables, as opposed to just setting their value in the class script (like property testProperty : “Default value of testProperty”).

You just have to make sure to end it with “return me”. Otherwise you won’t get an instance of your object when the app starts.


property instanceVar : ""
property instanceUser : ""

on init()
	set my instanceVar to "Value of instanceVar set in init()"
	set my instanceUser to (short user name of (system info))
	return me
end init