If I call this from applescript, I get error. It won’t return anything. I can call ibactions which are basically voids but I can’t figure out how to call a setter or getter in my obj c from my applescript.
#define myVersion 1.25
***********************************************************************
vnGet method - disabled for now
***********************************************************************
-(NSString*)vnGet
{
NSString* myVstring = [NSString stringWithFormat:(NSString *) @"%f",myVersion];
if (beta_version) NSLog(@"myVstring=%@",myVstring);
return myVstring;
}
script my_exampleAppDelegate
property parent : class "NSObject"
on applicationWillFinishLaunching_(aNotification)
set my_version_no to my application's vnGet
display dialog "Congratulations, you are running version" & my_version
end applicationWillFinishLaunching_
end script
This way I can put my version number in the Obj C header file or in the applescript file but not both. So of course I’d accept it the other way as well. But once again, I can call things from Obj c as long as I don’t try to pass anything but “self” (sender). Of course I’ve tried it with other data types including NSString and Boolean with no luck.
I’ve even thought about writing a floating point number to the info.plist and reading it back in from the other side but that seems stupid.
Am I missing something obvious here or is this really a limitation? All my research so far indicates this is a limitation but I can’t understand why Apple would build a little firewall that allows you to pass events and object pointers back and forth but not values.
Create a “blue box” (object) in the .xib. Then set it to represent your Objective-c file. In the AppleScript, add a property with missing value and in the xib connect it to the blue box. If you name the property otherFile, for example, then this is what you’d do:
Thanks for your help. Unfortunately I’m not able to get this working just yet. My app is an applescript cocoa app in xcode 4. I didn’t create an extra blue box as xcode provided one. Only all the methods look alike. They are
-(ibaction)dosomething:(id)sender
I can define a new one like getvn
-(nsstring)getvn
and it crashes
even if I do it like
-(nsstring)getvn:(id)sender
How about going the other way? Can I call an applescript function to return an nsstring to the obj c side?
When I have more time, possibly tomorrow evening, I’ll make a sample app I can paste in its entirety to illustrate the problem.
Sorry. I forgot the * in my post, not my code. The error I get in the console is something vague ( to me) about passing an unexpected value. Even if the code keeps running, the number I try to pass never makes it across.
I still think the best way to do this is through the nib. NSApp is leading me down a dark alleyway with no end
This
property myClass : class "MyClass" of current application
on applicationDidFinishLaunching_(aNotification)
set theVers to myClass's getVersion()
log theVers
end applicationDidFinishLaunching_
returns
The objective-c class MyClass .m file looks like this:
[code]#import “MyClass.h”
@implementation MyClass
(id)init
{
self = [super init];
if (self) {
}
return self;
}
-(NSString *)getVersion {
return @"2.5";
} @end[/code]
The error looks as if its not trying to access getVersion in the right way. It’s a method.
Notice that the error has a + sign: (+[MyClass getVersion]: unrecognized selector sent to class ). The way you are calling the objective-C method is for class methods only not instance methods like getVersion. You should do what you said in your previous post – add the blue cube, and call the method using a property connected to that cube. Or you could just make your getVersion method a class method. You also don’t need the init method, and in your applescript you don’t need “of current application” in your property declaration. If you have your property called otherFile you just need this:
property parent : class "NSObject"
property otherFile : missing value -- IBOutlet for the MyClass blue cube
on applicationWillFinishLaunching_(aNotification)
set theVers to otherFile's getVersion()
log theVers
end applicationWillFinishLaunching_
The other way to do it without adding a blue cube in IB, is just to do an alloc init in your code to create an instance of that class, like so:
property parent : class "NSObject"
on applicationWillFinishLaunching_(aNotification)
set otherFile to current application's MyClass's alloc()'s init()
set theVers to otherFile's getVersion()
log theVers
end applicationWillFinishLaunching_
But Info.plist is the designated location to store the version number and retrieve it from there.
Even the AppleScript command version reads the value from Info.plist
Use this to get the version number from the PList:
ASOC:
set dict to current application’s NSBundle’s mainBundle()'s infoDictionary()
set shortVersion to dict’s valueForKey_(“CFBundleShortVersionString”)
ceWindow’s setTitle_("Coupon Exporter " & shortVersion)
I’ll also add that the version number is NOT a real float. Look at Mac OSX: 10.6.8 -that’s not a number, it’s more like a special string. I’m using Sparkle for some of my apps, and it reads the version number from the Plist. If you say “1.25” as a version, then that is a higher number than “1.3”. I was using this sort of decimal notation but then ran into a problem where I couldn’t continue to use Sparkle properly because v2.20 was higher than v2.3… I had to use 2.30. The convention is x.x.x and like the cocoa method shows, it’s a string not a real number.
You can use the above code wherever you need and don’t even have to worry about passing things back and forth across objects.
First of all, I’ll move my version to the plist file. I’ve been using a math based method to compare versions so I’ll have to either use 1.20 instead of 1.2 or switch to 1.2.0.
Second of all, I’ll try passing an NSString from Applescript to xcode. This time the method will have a void return but will take an NSString from Applescript. I’ll try adding it to an existing class and see if I can make it work as shown here. If not, I’ll try adding another blue block just to check that option as well.
as the key CFBundleShortVersionString implies, the version information in Info.plist is indeed a string.
Cocoa provides a method to do a numeric comparison for strings
set dict to current application's NSBundle's mainBundle()'s infoDictionary()
set shortVersion to dict's valueForKey_("CFBundleShortVersionString")
set compareVersion to "1.10.2"
set comparisonResult to shortVersion's compare_options_(compareVersion, 64) as integer -- 64 = NSNumericSearch
if comparisonResult is 1 then
log ((shortVersion as text) & " is higher than " & compareVersion as text)
else if comparisonResult is 0 then
log ((shortVersion as text) & " is equal to " & compareVersion as text)
else if comparisonResult is -1 then
log ((shortVersion as text) & " is lower than " & compareVersion as text)
end if
How would you do such a comparison in obj c? What I’m doing ( and getting away with for the moment) is this…
if( text )
{
double newVN = [text doubleValue];
if ([myVersion doubleValue] >=newVN) {
update_avail = NO;
if (beta_version) NSLog(@"No update_avail, Text=%@", text);
}
else {
update_avail = YES;
if (beta_version) NSLog(@"YES update_avail, Text=%@", text);
}
I don’t quite know what cocoa makes of “doublevalue” of something like 1.2.3.6 so I’d love to see the equivalent string comparison as integer methods you showed earlier for applescript for obj c.
Edit: Ok, an NSLog reveals cocoa thinks 1.1.7 is 1.10000. Not gonna quite work so yeah I need the cocoa equivalent of set comparisonResult to shortVersion’s compare_options_(compareVersion, 64) as integer.
On the original topic, sadly I cannot pass anything across the impenetrable applescript/obj c barrier yet. I tried a few things but they resulted in errors similar to the unrecognized selector mentioned earlier in this thread.
At this point, now that I’ve got version working to my satisfaction (other than the compare thing in objc), I’m wondering how to pass an NSString from applescript to obj c. That’s the last piece of the puzzle I need for the project I’m working on tonight.
Ok here we go. I want to pass an nsstring over to objc from applescript and different nsstring back again.
I whipped up. No I got whipped up on by a test app… Oops. I see one mistake already. I shouldn’t have said tell foo. I should have said tell theclass. Be right back… Ok done. Same result. Fixed “foo” typo and still get ugly dump. I’m sure I’m missing something obvious but I can’t see the forest for the trees.
script AppDelegate
property parent : class "NSObject"
on applicationWillFinishLaunching_(aNotification)
set theclass to current application's foo's alloc()
set teststring to theclass's itell
log teststring
tell theclass to tellme("bogus")
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
end script
Produces the rather prolific console output as follows…
2011-11-02 20:39:44.686 test123[92229:407] [<foo 0x400aea180> valueForUndefinedKey:]: this class is not key value coding-compliant for the key itell.
2011-11-02 20:39:44.693 test123[92229:407] (
0 CoreFoundation 0x00007fff987ed286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff973bbd5e objc_exception_throw + 43
2 CoreFoundation
I don’t know why you are trying to convert the version “number” to a number. As Stefan showed, NSString has methods for comparing strings that work fine for this kind of string. Here is objective-C code that a does the same thing as Stefan’s code. Note that to pass a string from ASOC to objective-C, you just have a string as the argument to the method you are calling (compareVersions: in this case). It doesn’t have to be an NSString, an applescript string will do just fine.
script VersionTestAppDelegate
property parent : class "NSObject"
on applicationWillFinishLaunching_(aNotification)
set compareVersion to "1.2.5"
set otherFile to current application's MyClass's alloc()'s init()
otherFile's compareVersions_(compareVersion)
end applicationWillFinishLaunching_
end script
The objective-C file is:
@implementation MyClass
-(void) compareVersions:(NSString *)compareVersion {
NSDictionary *dict = [[NSBundle mainBundle] infoDictionary];
NSString *shortVersion = [dict valueForKey:@"CFBundleShortVersionString"];
NSComparisonResult comparisonResult = [shortVersion compare:compareVersion];
switch (comparisonResult) {
case 1:
NSLog(@"%@ is higher than %@",shortVersion,compareVersion);
break;
case 0:
NSLog(@"%@ is equal to %@",shortVersion,compareVersion);
break;
case -1:
NSLog(@"%@ is lower than %@",shortVersion,compareVersion);
break;
}
}
@end
Notice that I use just use the simple compare: method rather than compare:options: method that Stefan used – I found that this works better. Using the NSNumericSearch option gives 1.25 as higher than 1.3 whereas the simple compare: method gets this case right (both work fine if you stick to the x.x.x type of format with only one digit between each dot).