I’m moving an AppleScript Studio project to ASOC and have run into a problem. My script is around 8000 lines of code, and around 6000 lines it throws an Internal Table Overflow (-2707) error. I need to split it into separate smaller scripts. It’s mostly lots of discreet handlers, so I can easily move chunks of it, I’m just not sure how. Should I put them in separate scripts and then use Load Script in the main script? Or do I make calls from one script object to another?
First, I’ve seen that same error in 100 line scripts, so the error isn’t necessarily related to the length of your code (I don’t know if it’s even possible that the length of your code could cause that error). That being said, I do think it would be better to break up your app into separate scripts. I can’t really comment on the relative merits of using load script vs keeping the scripts separate and making calls to them. I think the goal should be to break the program up in such a way that there doesn’t have to be a lot of calls between the different scripts. It’s my understanding of object oriented programming, that each object (or class) should take care of its own business as much as possible. I can’t say how possible that is in your app without knowing how it’s structured.
Ric
Ric is right
This examples shows you
the 8000 lines of code shouldn’t be the problem. But that doesn’t answer your problem.
It depends on what the job is of the code. When it is a library (chunks of code that is wrapped in handlers) you can use load script without problem. When it is more like a class (it contains properties and need to get inside the ObjC - runtime) you should create an AppleScriptObjC class for it. However it won’t harm to create for everything a AppleScriptObjC class.
The reason I’m thinking it’s length is that I got this from an engineer at Apple:
I’ll fiddle with Load Script and see if I can get it working. Thanks!
I’ve put a bunch of my functions into Cocoa classes and I call them in this fashion:
–declare the class here
script Your_Application_AppDelegate
property parent : class “NSObject”
property CocoaHelpers : class “CocoaHelpers”
…
then later call the method and pass it any vars:
CocoaHelpers’s removeXDayOldFiles_((POSIX path of (archive3Path as string)))
or I’ve also done a “load script” method. In my case, this is pretty complex because I have about 20 files and I prefixed the name of the actual file with a short code. Then I do a repeat to load them all, and store the name of the script too in an array. If you want more detail on that I can provide it but it’s not what I’d call “all purpose” the way I did it.
I’m pretty sure that’s out-of-date.
Ric and DJ are correct that you can get the problem in quite short scripts, but script length can definitely be a factor. I had a case recently where I was storing info in comments of every line of a script, and deleting the comments made the errors go away.
Unfortunately the whole thing is hard to pin down – in my case, the same script had to be run several times consecutively to provoke the error; I could otherwise run it a couple of time, run something else, and so on.
Anyway, multiple scripts is the way to go. But I’d definitely be breaking it into classes rather than using load script. It makes it much easier if (when?) you decide to refactor your code.
Thanks for all the help guys. I’ve got just one more problem (famous last words).
I’ve never worked with multiple classes like this, so I’m a little confused about messaging. I’ve built a test project and created a second class. My main script has this code:
script multiple_class_test
property parent : class "AMBundleAction"
property DialogClass: missing value
on runWithInput_fromAction_error_(input, anAction, errorRef)
-- Add your code here, returning the data to be passed to the next action.
DialogClass's sayThis()
return input
end runWithInput_fromAction_error_
end script
And my other class has this code:
script DialogStuff
property parent:class "NSObject"
on sayThis()
display dialog "blah blah blah"
end sayThis
end script
When I run it, it works fine, displaying a dialog box that says “blah blah blah.” So then I tried to rig it to allow me to pass a string to the dialog class, and did this in my main class:
script multiple_class_test
property parent : class "AMBundleAction"
property DialogClass: missing value
on runWithInput_fromAction_error_(input, anAction, errorRef)
-- Add your code here, returning the data to be passed to the next action.
DialogClass's sayThis_("I'm some text")
return input
end runWithInput_fromAction_error_
end script
And this in my dialog class:
script DialogStuff
property parent:class "NSObject"
on sayThis_(aString)
display dialog aString
end sayThis_
end script
But when I run it, nothing happens, and it logs this error:
[DialogStuff sayThis:]: «class ocid» id «data kptr00000000A0F0480004000000» doesn't understand the «event sysodlog» message. (error -1708)
Help!
on sayThis_(aString) display dialog aString end sayThis_
This needs to be:
on sayThis_(aString)
display dialog (aString as text)
end sayThis_
Whenever you pass arguments between script classes, they get converted to Cocoa objects; you need to coerce them back to AS objects on arrival.
Got it. Thanks, Shane, that’s working now.
Next problem:
I’ve defined a property and linked it to a text field. I’m able to set the contents of the field using the field’s setStringValue method. The field is bound to a parameter, but the parameter is not getting the value that I’m placing into the field. In AppleScript studio, I needed to explicitly set the parameter. What do I need to do in ASOC?
If you bind a property to the value of a text field, the property normally won’t change if you change the value programmatically. Is there some reason you don’t just set the value of the property instead? Perhaps a bit more detail is in order.
Well, I suppose the main reason is that I can’t figure out how to set the property directly. I know how to read stuff from the parameters, for example:
set parameters_dictionary to my parameters()
set passSaved to parameters_dictionary's valueForKey_("passSaved")
But I don’t know what method to use to set a parameter.
The opposite of valueForKey_ is setValue_forKey_.
So if I do this:
set parameters_dictionary to my parameters()
set thePath to choose folder
photoshopSaveDestination's setStringValue_(thePath as string)
parameters_dictionary's setValue_forKey_(thePath,"photoshopSaveDestination")
Does that actually change the parameter value?
What is photoshopSaveDestination? Is that a text field? I can’t really tell what you’re trying to do. Your last line will create a dictionary entry (if parameters_dictionary is an NSDictionary) with a key of “photoshopSaveDestination”, but that doesn’t have anything to do with your text field (if that’s what it is). However, parameters_dictionary won’t be an NSDictionary if parameters() is not a dictionary. Maybe you should describe what you are trying to accomplish here, so we could offer better help.
Ric
Does that actually change the parameter value?
Yes.
I presume by your use of parameters() and parameters_dictionary you’re working on an Automator action. Have you checked out the sample ASObjC code for that?
Right, sorry about that, I’m working on an Automator Action.
I’m just trying to rig up a way for the user to select a destination folder for some output. So, I’d like them to click a button, get a choose folder dialog. In the previous example, photoshopSaveDestination is the parameter where I save the destination path, while photoshopSaveDestination is a text field where I display the folder the user selected.
That code is all wrapped up in a handler for the button they click to choose the destination path. However, the code doesn’t seem to be actually changing the parameter, but it does properly update the text field.