Losing global variables and refs when adding obj-C to AS

Wow. This one is driving me nuts.

I am a competent AppleScript developer, and I’ve been working for a little while with AppleScript Studio. Most recently I have been working on an application that includes quite a number of global variables and some slightly complex GUI components (text view inside of scroll views inside of tabs inside a window…). Running it as an AS application is no problem: everything goes smoothly.

Then the fun begins. I add an external objective C class that I want to access by the applescript “call method” (though I have a couple controls that hook up directly to functions via the “actions” panel in the IB inspector) and while that integration has been a puzzler for a non-cocoa person like me (any good references about how to do that?), my big problem has to do with my applescript. The application compiles without trouble (no errors or warnings), but as the main window application comes up, I get quite a number of alerts along the lines of “can’t make «class » id 39765 into type reference (-1700)”. And I get this same message every time I try to change tabs in the main window (clicking on a new tab), or anytime I click on a control that sends an action to something defined contextually (such as: ‘set contents of text field “main text” of tab view item 1 of tab view “tabs” of window “main” to “this is some text”’). Moreover, although I have properly set global variables at the beginning of the script, they don’t seem to be recognized as global: only local variables are working!

I’ve done quite a bit of testing, and it seems that my script is no longer able to remember or relocate tab view items without generating this same error.

Is this due to the addition of the C class somehow?

Anyone have any ideas? I’ve taken my GUI controls apart bit by bit and re-added them in the project, naming things carefully, and I always get the same result. Meanwhile, the version of the project without the objective C class runs fine.

Browser: Firefox 3.0.1
Operating System: Mac OS X (10.5)

Hi,

“can’t make «class » id 39765 into type reference (-1700)”
is a referencing error, something is missing in the reference chain.
I recommend to replace the global variables with properties.

Thanks, Stefan. However, I wish it were that simple. Here’s a great illustration of the problem I’m having: look at this macscripter post
http://www.macscripter.net/viewtopic.php?id=24212. It shows a pretty standard way of getting a hold of tabs so they can be referred to later: you create properties for objects, and then you set them, as this code from my project:

on awake from nib theObject

set windowMain to window "main"
set tabMain to tab view "tabs" of windowMain
set recordTab to tab view item "recording-tab" of tabMain
set dataTab to tab view item "data-tab" of tabMain
set prefsTab to tab view item "prefs-tab" of tabMain
display dialog (tabMain as text)

end awake from nib

In my regular AS Studio project, this kind of thing works fine. In the version with the Objective-C class added, all heck breaks loose, and each of these set statements triggers the “can’t get class…” error.

Note, however, that it doesn’t seem to be a referencing error as such, for I can get the name of a tab through a standard way:

set recordTab to name of tab view item “recording-tab” of tab view “tabs” of window “main”

In that case, I get the name of the item, but I can’t grab it as a reference. Any other thoughts?

If the errors occur only using the Obj-C class, then something might be wrong either with the call of the method or with passing and returning the parameters
You can also try to use this syntax in the awake from nib handler

set x to a reference to tab view item .

The strange thing is that I’m not even implementing the call method yet, or passing any parameters with the Objective-C class.

Thanks for your tip. I tried your reference suggestion, and it worked, partially: I am at least able to set the property to a reference to these items. But I still can’t do anything with this reference. For instance, here’s the current code:

        set tabMain to a reference to tab view 1 of windowMain
	set recordTab to a reference to tab view item "recording-tab" of tabMain
	set dataTab to a reference to tab view item "data-tab" of tabMain
	set prefsTab to a reference to tab view item "prefs-tab" of tabMain
	set current tab view item of tabMain of windowMain to recordTab

It’s all fine until that last step, which throws the same kind of error: "Can’t make tabMain of «class » id 40391 into type reference. (-1700). But just three lines above, I did exactly that: I set tabMain to a reference!

I’m wondering if there is some crazy initialization I should be doing because of the Objective-C class. That class is a third-party library of a few files, and I have never before added a class to an AS Studio project (and I know squat about Objective-C). Is there some reference I should be looking at to see if I integrated that properly?

90% of the applescript studio problems I see are referencing problems. What you’re doing in the awake from nib handler is not the best way to get references to your objects as it still leaves the door open for referencing errors. There’s a simple solution to make sure your reference to an object is undeniably correct. Give the object you want to reference an applescript name and hook it up to the ‘awake from nib’ handler in interface builder. Then in your code do the following, for example if I wanted to reference a text view (named myTextView in interface builder) which is inside a scroll view which is inside a tab view item which is inside a tab view which is in a window…

property myTextView : null

awake from nib theObject
if name of theObject is “myTextView” then
set myTextView to theObject
end if
end awake from nib

That’s it. Your variable myTextView will get the object’s reference itself and you don’t ever have to worry about getting the reference wrong. You don’t need a reference to your tab view or your tab view item either because theObject defines myTextView for you. You can even move that text view to another location in your application’s interface and your reference will remain correct.

One other thing you need to know about tab views. Suppose you have 3 tab view items in your tab view. When your application launches one of your tab view items is visible, and two of them are not. The objects inside the two tab view items which are not visible do not get created until the tab view item is activated. Considering this you have to be careful not to do anything with those objects until after the tab view items are activated.

I hope this helps.

couldn’t work, because tabMain already includes a reference to windowMain
try this


property tabMain : missing value
property recordTab : missing value
property dataTab : missing value
property prefsTab : missing value

on awake from nib
	set tabMain to a reference to tab view "tabs" of window "main"
	tell tabMain
		set recordTab to tab view item "recording-tab"
		set dataTab to tab view item "data-tab"
		set prefsTab to tab view item "prefs-tab"
		set current tab view item to recordTab
	end tell
end awake from nib

calling Obj-C classes from AppleScript is quite easy, a special initialization is not needed in the most cases

I really appreciate all this help. I just wish it was working.

First, to reply to regulus, what you say makes eminent sense, and it is pretty close to how I started out. But it’s not working in this project. Here’s my code to test your setting to the tabs to a variable via the name (and then cycling through the tabs to make sure they get created before anything else happens in my code):

on awake from nib theObject
if name of theObject is “tabs” then
set tabMain to theObject
else if name of theObject is “recording-tab” then
set recordTab to theObject
else if name of theObject is “data-tab” then
set dataTab to theObject
else if name of theObject is “prefs-tab” then
set prefsTab to theObject
end if
set current tab view item of tabMain of window “main” to recordTab
set current tab view item of tabMain of window “main” to dataTab
set current tab view item of tabMain of window “main” to prefsTab
end awake from nib

Problem is, I get the same “can’t make… into a reference” error at the very first step.

Now, for Stefan, look at this code, which displays a dialog at each step (could have logged it, but am using display dialog here):

set tabMain to a reference to tab view "tabs" of window "main"
display dialog "1"
tell tabMain
	set recordTab to tab view item "recording-tab"
	display dialog "2"
	set dataTab to tab view item "data-tab"
	display dialog "3"
	set prefsTab to tab view item "prefs-tab"
	display dialog "4"
	set current tab view item to recordTab
	display dialog "5"
end tell

That’s basically your suggested code. What happens? I get an error before dialog 1 (can’t make… in reference). HOWEVER, steps 2, 3, 4 go smoothly (though I don’t see how that’s possible if step 1 failed). Step 5 fails, with the same “can’t make” error.

Methinks it is bedeviled! I can post the project if anyone wants a closer look.

You can’t say this…

set current tab view item of tabMain of window “main” to recordTab

The variable tabMain already knows it is part of the main window. That’s the beauty of my method i.e. you only need to use the variable and no other reference to any other objects. As such try this instead…

set current tab view item of tabMain to recordTab

Second problem…
You can’t use those statements in the awake from nib handler because you are referencing variables before they have been created. Meaning your staements get called before all of your objects ‘awake from nib’. What I do is use the application’s ‘on launched’ handler to initialize my stuff thus I am sure that all of my variables are set before I use them.

Then either the tab view or the window isn’t named properly in Interface Builder
or there is a missing UI element like a box or another view between the window and the tab view

Stefan, I fully understand your assumption that the naming is wrong, or that there is an intervening element. But I’ve checked this a zillion times (once again after you message), and there is no problem there.

Regulus, I’ve tried your syntax, and move the current tab setting to “on launch”, but no dice. I’m still getting can’t make… into reference errors.

Again, this is not happening in the basically identical project without the Objective C class. Terribly puzzling.

Just to explain how I handle the flow of launching my application…

In interface builder…

  1. I hook up the application object to the will launch and launched handlers.
  2. I hook up my objects to the awake from nib handler
  3. I unhook my main window from “visible at launch”

In xcode…

  1. the will launch handler gets called first. I use that to read in my preferences plist file.
  2. The awake from nib handler gets called second. I use that to define my variables for my objects.
  3. The launched handler is called 3rd. I use that to initialize anything in my application. At the end of the handler I show my main window with the command…

show mainWindow

If I show the main window last in the ‘launched’ handler then I know that all of my interface objects have been taken care of (initialized) before the window becomes visible to the user.

If you’re still getting reference errors then it’s not your references that are incorrect. It must be that you are calling an object that hasn’t been instantiated yet. Try this with your code…

on launched theObject
If tabMain is not null then
if recordTab is not null then
set current tab view item of tabMain to recordTab
end if

if dataTab is not null then
set current tab view item of tabMain to dataTab
end if

if prefsTab is not null then
set current tab view item of tabMain to prefsTab
end
end
end launched

This will make sure your objects are defined before you try to do something with them. Of course if you have your property variables set to missing value instead of null then use missing value.

Thanks, guys. I have to dash right now, but I’ll try these suggestions later today and report back. This sounds promising.

Egads. still not much luck. If I put a display dialog “1” at the VERY beginning of “on awake from nib theObject”, I ALREADY get a “can’t make class…” error before that dialog even appears. So, before anything in the script tries to do anything, an error is thrown.

Have you seen this post:?

http://macscripter.net/viewtopic.php?id=27337

In XCode 3 there is a bug that does not let you set a variable to reference a tab view. You have to actually call it by long form every time (tab view item of tab view blahblahblah). In XCode 2.5 the same code to variable a tab view works OK.

I also disagree with this from Regulus:

The tab view object are created in IB and are ready to go. I don’t have it at hand, but I my latest app sets several variables and startup settings inside a tab view that is not yet visible. It works OK.

Does this help?
Chris

Chris, Thanks for your suggestion. Your experience is similar to mine in other applications. However, the problem here is that even if I call the tab the long way, I am still getting the error message. As I mentioned, I’m getting an error message even before the on wake from nib handler goes into effect, which has me wondering if there is some interference between controls that are referenced to the applescript but also named for use in the Objective C class.

Again: in a copy of this project that is virtually identical, but without the Objective C class, I am able to reference tabs, set the contents of fields in tabs that have not yet been activated, etc., etc. It’s this particular version that is throwing quite a number of errors – as if the memory was getting wiped after ever handler (or as if globals and properties only worked like local variables).

I’m beginning to think that I’ve incorporated the Objective C class incorrectly, or that I have crossed a wire between Objective C and applescript, but I can’t locate any documentation on how I should add such a class.

I suspect people are getting burnt out on this topic, as I’m not making much headway. If anyone wishes to take a peek at the code, let me know and I can send it offline.

Scott

Yes Chris you’re right, I tested it. But let me explain my statement a little more…

I talked about setting up a variable in the awake from nib handler to reference an object in a tab view item. Initially the variable is set to null. If I use the variable for an object before the tab view item has been activated then I get an error because at that point my variable is still set to null. The object in that tab view item does not call its ‘awake from nib’ handler until that tab view item has been activated so my variable remains null until the tab view item is activated. However I can reference that same object the long way without any errors. I just can’t use my variable reference. Objects which do not call the ‘awake from nib’ handler at application launch (which includes objects in tab view items) is where my variable system has a little problem, although it’s still not difficult to use if you understand what’s going on.

So to be clear, this does not work until a tab view item is activated…
set content of myObject to “something”

But this does work whether a tab view item has been activated or not,
set content of text view “blah” of scroll view 1 of tab view item “blah” of tab view 1 of window 1 to “something”

Scott, I’ll take a look at it. I’ll send you an email offline.

Well, for those following this sad saga, let me provide a little update. After much messing around and some consultations, the problem is sadly unresolved. At present my best guess is that some interference is occurring between the objective-c class (and it’s appdelegate and bindings) and the applescript studio portion of the application. It appears that interface interactions are being handled first by the Cocoa portion of the app, before getting routed to applescript, and en route some information is getting lost.

If anyone has further suggestions, I’m all ears. But I suspect this one is not easily solved.

If anyone can point me to other samples of applescript being integrated with Objective C projects, I’d much appreciate it.

Hank,
Ah I see what you’re saying. Thanks. :smiley: