I am beginning to work on what will eventually be a rather large application. Consequently, I am going to need to work with more than one AppleScript (class). I understand how to create a new script (class) through File, New->, New File., Other → Empty. That creates MyScript.applescript(s)
However, it is at this point I am lost. I can add handlers to these new scripts, but I cannot access them. I suspect I have to drag the blue cube “NSObject” icon into my Objects, and they do that (somehow). However, then what? That is, how do I connect the “NSObject” to the script? Do I have to change the Class Type?
Can a handler from one script call another handle?
Also, does anyone have some rather sage advice on when to break programs into multiple scripts and/or .xib’s?
I think this topic of breaking applications into multiple classes and xib files is quite a complex one. First, the blue cube thing – you don’t always need to have the blue cube, it’s just a proxy for you script that allows you to expose the class’s methods and properties in IB so you can connect them. So, if you have classes that don’t need to be connected to anything in a xib file, then you don’t need one. When you do use one, you do change the class to that of your script.
Sure, you can create a property and hook it up to the blue cube, to get a reference to the other script, and call things with “otherScript’s myMethod_(some argument)”, where otherScript is your IBOutlet to another script’s blue cube. If the other script doesn’t have a blue cube, you can still call methods in it by instantiating it in code: “set otherScriptObject to current application’s OtherScript’s alloc()'s init()” where OtherScript is the name of another applescript file.
I don’t know about the sage part, but I can give you my two cents. First, it’s my understanding of object oriented programming (OOP) that objects should handle their own business as much as possible, so when I break a project into multiple classes, I try to do it in a way that doesn’t require that each class have outlets to lots of other classes – each class should “do its own thing” as much as possible. For instance, I have a program that keeps track of plants in my garden, and I have a class called RDPlant that creates new plants with some initial characteristics. I can call the designated initializer for a plant from another class with “set newPlant to current application’s RDPlant’s alloc()'s initWithPlantName_cultivar_action_date_”, and that’s the only way I need to access that class in a direct way. All the other methods in that class are instance methods, so I can just use them directly with the newPlant object like: newPlant’s addAction_(“transplanted outside”), just like you would access any of the NSString instance methods once you’ve created the string with one of the class’s initializers. You still will probably need some outlets to other classes, but I think that should be kept to a minimum – the classes shouldn’t be broken up just to save scrolling in your main script, there should be some functional reason for why you make the split.
As for xib files, I think the main reason to break them up is to keep your memory footprint down (and also to simplify the file so it’s easier to understand). If you have windows that aren’t needed most of the time, then they might be good candidates for putting in separate xibs, so you can just load them when you need them.
I would be glad to hear other people’s perspectives on this topic, since it’s one that I’m still learning about.
No, some objects like File’s Owner, First Responder and Application are placeholder objects, they are there so you can connect hem. The other objects, like windows and the blue cubes of your own classes, are Interface objects and are actually created when the NIB is loaded.
The step from procedural programming to object oriented programming is a big one. You should stop thinking in scripts and start thinking in classes and objects. See an application as a collection of object behaviors, not as an instruction list. When your program should do something, consider which object should do it and implement the functionality in its class. Every class usually has its own file so start a new file when you need a new class.
Each NIB contains Interface objects that are loaded and used together. Usually the application NIB contains the menu bar and everything that should be loaded at launch time. There are separate NIBs for each window and can be loaded multiple times, for example for each opened document.
Thanks everyone, for your comments. It is good to hear that I am not the only one who thinks this is worth discussing. Perhaps we could get some input from Shane Stanley?
Shane: I do not know if you wrote “AppleScriptObjC Explorer 2” in AppleScriptObjC or not, but if you did, you certainly ran into these issues. That is a very complex application. What do you suggest?
What I am hoping to find is not only how to do this, that is, use multiple scripts and access handlers from within other scripts, but also some advice on when this should be done. Another words, how big is too big; when is it best to have a common set of reusable routines vs. simply recoding?
One issue that I am about to tackle is that I have a number of dialog boxes that use a pop down list within them. Each pop down list contains the same data in them. I would like to have a handler or two that handles these pop down lists within a “common” class or script that I can use over and over again (a library of reused objects). Obviously, I would rather not have to rewrite them for every dialog, and I do not think that is necessary, but I am having trouble seeing how to refrain from doing that.
There is a blue cube created for the app delegate when you create a new project, but that’s not true if you add new classes – you have to add the blue cube manually, if you want (or need) to have one.
Yes you do change the class, in fact, you must in order to have the cube represent your new class – just select the cube and select the name of your class from the pull down menu in the Identity Inspector. After doing that, if you right click on the cube you will see any methods and properties that you’ve added to your new class.
Does anyone know of a publicly available LARGE project that might be downloadable and useful. All these small routines are very useful, but I would like to see how a more complex project works.
You have to think the other way around and put the handlers in the class where they belong, this is the class whose responsibility it is. You will have smaller and larger classes. If a class gets a lot of responsibilities, if you have to scroll a lot or if you get lost in your file, it is time to delegate tasks to other classes.
Again, you have to ask: who is responsible for this list? and put it there. You can make the list a property of the application delegate and connect to it by bindings. If the dialog boxes are related, you also can make the controllers (subclasses of) the same class and assign the list in awakeFromNIB.
A class doesn’t have to be in a NIB, there are other ways to instanciate them.
When the NIB is loaded, an instance (= object) of each of the blue cubes and other objects is created. If you load the NIB four times, you have four copies of each Interface object in the NIB. You can also put three blue cubes of the same class in one NIB, you get three objects of that class. A blue cube doesn’t represent a class, it represents an object. A class and an object are different things, an object is an instance of a class. AppleScript script objects and AppleScriptObj script objects look the same but they are different. An AppleScript script object is kind of an object and an AppleScriptObj script object is a class.
You will get lost in a large project made by someone else. Like StefanK said, take a look at Apple’s samples. A lot of them are a small sample of something you probably don’t need but TextEdit, Sketch, Departments and Employees, iSpend and FunHouse are samples of (little) applications.
Before you start your large application, do some practicing on a small one. It took me a year to understand the Cocoa design patterns and I had previous experience with oop and frameworks. Halfway through my first Cocoa program I decided to start all over again because the design was wrong.
I wrote the initial version about 95%+ in ASObjC, and the final version 1 was probably about 75% ASObjC. The current version is about 99% Objective-C – only the bit that can’t be Objective-C is still in AS.
The driving force for the change was things like code-completion – that involves building lists of 10s of thousands of terms, and searching them after nearly every keystroke. There are also places where being able to multithread makes it more responsive.
That said, I was amazed at what I could do with ASObjC. And doing it there first was, for me, a great way to go; I was able to get it working and prove what could be done, then rewrite it a bit at a time, starting with the bits where performance matters.
As for the overall design and structure, that’s something that regularly changed. You can start off with an idea of how to approach things, but invariably you will be changing approaches. This is especially so when you start using APIs for the first time, but I think it’s just the nature of programming.
As an example, I started off using an OSAView for the script pane. It’s relatively simple to use, and probably what Xcode used in v3. Then I found that it’s buggy; it can’t undo through compiles, and if you try, it stuffs up the undos and can make a complete mess. (This could happen in Xcode.) So I ended up with a heavily modified subclass of NSTextView. And that meant lots of other things needed to be rearranged.
The browser that shows files included in the bundle was another area that I refactored many, many times. Each time I thought I had it right, I realised I needed to redesign it. I finally had it working fine – and Lion’s duplicate command combined with restoration completely broke it again. It ended up being probably the most time-expensive part of the project (and one that probably very few people use – sigh).
I guess what I’m saying is that sometimes the best thing to do is dive in, and be prepared to change tack regularly.
When I worked as a programmer in a team of experienced programmers and every hour had to be payed, we first made a description of the program, including the technical solutions. Next we did the programming as described. It rarely happened that we had to change the design. The designing, reading the documentation and sometimes a little experimenting was done in the first step. Programming can be straight forward.
Been there, done that, many times. Now I’m programming as a hobby I just dive in.
Even so, refactoring code regularly seems to be a fact of life for a lot of Cocoa programmers, if the mailing lists and book authors are to be believed.
I’m sorry, my English (not my first language) is bad. Years ago I was a professional programmer. I was working in a team of programmers. Diving in was not allowed. We first had to make a design specification and a planning. The design and structure changed during the specification process. The programming was done according to the specification and not by trial and error. By my experience the nature of programming is straight forward. I can’t design and program at the same time. I can design, research, experiment and read documentation at the same time.
New API isn’t difficult, new concepts like OOP (Object-oriented programming), MVC (Model-View-Controller) and KVO (Key-value observing) are difficult, especially when you are used to other concepts.
Is the refactoring done because of wrong design or because of new technology/functionality?
Oh, I understood what you were saying – I was just pointing out that most of us here aren’t what you’d call professional programmers.
All three. Sometimes simple wrong (or short-sighted) design. Other times because new requirements require it, or because of new technology in the form of new APIs, or simply new knowledge. Good apps for Macs and iDevices tend to be continually changing.