Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > I'm missing something about Cocoa?

I'm missing something about Cocoa?
Thread Tools
Gametes
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status: Offline
Reply With Quote
Apr 10, 2003, 07:40 PM
 
As my project gets bigger, and I add more methods and objects, I'm running into a geometrically growing problem.
Namely, I want the objects to message eachother to get information and perform functions. But the objects don't know about each other unless I specifically hook them up together in interface builder. I quickly realized that connecting 5 objects together was more work than connecting them all to a central object (24 methods vs 10). But even now adding new objects means adding a flurry of new methods and keeping them all straight is a major pain.

Surely there's some easy inbuilt way to make all classes aware of each other in some "public playground", right?

So, how are you suppossed to handle this? What am I missing about classes, objects, and all that stuff?
I can't continue like this, because adding one more object that needs to use 4 others is going to amount to adding 4 methods to the new class, 8 methods to the controller class, and then 4 methods to other classes (16 methods just to do the work of 4). Then I have to reimport all of these into interface builder! Ahhhhh!!!

What am I doing wrong!?
you are not your signature
     
Chuckit
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status: Offline
Reply With Quote
Apr 10, 2003, 09:10 PM
 
Classes are all aware of each other. This is how it's possible for you to call [NSObject new]. It sounds to me like your problem is not thinking out your program design beforehand--you're just creating objects all willy-nilly. Part of making an OO program is figuring out how the different components should interact. Look at the Cocoa frameworks for some examples of how to structure things right.

Some things you might want to ask yourself:
- Should these all be separate classes, or would they make more sense as one?
- Do the classes form units that would logically comprise some larger class (like a document)?
- Is there some identifying feature of the class' instances that should be used to call them (like with NSImage's imageNamed: method)?
- Would some classes make more sense as an NSWorkspace-style shared-instance class?

Really, I don't see why you need this many classes in a single nib. That leads me to believe you haven't come up with the right class divisions.
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 10, 2003, 11:47 PM
 
It does sound like you need to rethink the design of your classes.

I usually wind up with a single "controller" object that is the owner of a particular nib. I rarely ever have other "instantiated" objects in my nib, just GUI widgets. My "controller" has outlets and actions that my GUI stuff connects to.

If my controller does use other (non-GUI) objects, it instantiates them in its 'init' or 'awakeFromNib' method and stores them in instance variables. If those objects need to communicate with other objects that are owned by the controller, they just tell the controller to do it, and the controller routes the message.

So, I wind up with big, giant controller classes that manage lots of simple little view (or helper) objects.

Hope this helps!
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
Gametes  (op)
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status: Offline
Reply With Quote
Apr 11, 2003, 12:19 AM
 
I have a Controller class, a delegate for each of the two NSBrowsers in my nib, an NSToolbar delegate, and a special text-handling class.
That's 5 classes, each of which must interact with a few of the others in a variety of ways. What I'd like to do is just make it so that they all just "know" the others are there, and can send messages to any of them. But for them to interact, I have to go through the controller class, which is the only one that knows about them all.

So I end up with:

(in browserDelegate1) [controller tellBD2ToDoSomething:thing]
(in controller) [BD2 doSomething:thing]
(in browserDelegate2) [self something:thing]

which gets really old when I have 4 classes which are delegated for GUI objects having to interact.
you are not your signature
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 11, 2003, 04:49 AM
 
Well, you can always do something like this from your controller so that the delegates can call each other directly. You'd do this in awakeFromNib or wherever you instantiate the delegates:
Code:
[browserDelegate1 setBrowserDelegate2: browserDelegate2]; [browserDelegate2 setBrowserDelegate1: browserDelegate1];
Your setBrowserDelegate methods shouldn't retain the parameter because if they do you'll have retention loops and nothing will ever get released.

By the way, in the example you posted, controller can just call 'something' directly, as
(in controller) [BD2 something:thing].

Also, it's perfectly okay to use your controller as the delegate for both browsers. That's how I usually do it, but I tend to create "god classes" (classes that have everything but the kitchen sink implemented in them).
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
ambush
Banned
Join Date: Apr 2002
Location: -
Status: Offline
Reply With Quote
Apr 11, 2003, 08:52 AM
 
Well you could use singletons.

something like +sharedInstance that will alloc init your object if it's not already alloced and return it... and it's a class method (+) so you doN't need an instance to perform it.

That's what I use for inter - manager/controller comm...

you can search on cocoadev/centrtal or stepwise, they tell you how to use it.

I'm currently coding an app, and just thinking about the object layout takes a lot of time.

You have to divide the tasks very well....

I suggest you to read the OOP docs out there and learn about the model view controller paradigm...
     
Gametes  (op)
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status: Offline
Reply With Quote
Apr 11, 2003, 10:26 AM
 
*sigh* ya I've read those docs.
I was just hoping that there was a less code-intensive way. I see that this is the logical way to keep everything clear, but my experience so far with programming languages has been that right after they show you the clear, logical way the language implements something, they show you a shortcut hack built above it because the language authors, too, got sick of doing it the original way...

As you can see, I only have 1 class that isn't directly tied to a GUI object (and of course there's controller) because that's going to be part of my reusable codebase framework for future apps, so I think I have things pretty well planned out.
As for combining browser classes: they model different structures so having a bunch of if clauses with methods to determine which browser I was dealing with would be more code than just using controller to communicate between them. That and debugging would have been that much harder.

Thanks anyway, I was just hoping for a way to declare program-wide objects like you can declare program-wide variables.
you are not your signature
     
wadesworld
Grizzled Veteran
Join Date: Apr 2001
Status: Offline
Reply With Quote
Apr 11, 2003, 05:30 PM
 
The same problem occurs in C++ programming.

Although lots of texts likely to mention things like "object simply pass messages" to each other, they forget to mention that that means lots of objects must have pointers to other objects and therefore objects end up including the headers of all sorts of other objects, which in turn include that objects header, etc, etc.

In short, it can turn out to be a large mess.

There's three basic strategies:

1) Have the objects all (or mostly) know about each other. As described above, this may be the most direct solution, but it quickly becomes unmanageable.

2) For a smaller project, define a centralized controller that handles the message passing.

3) For a large project, design a more heirachial approach. For example, you might have multiple controllers that handle the message passing for objects under them, and they pass messages between each other. So, you have a GUI controller, a FileSystem controller, a LogicController, whatever.

Wade
     
3.1416
Dedicated MacNNer
Join Date: Feb 2001
Status: Offline
Reply With Quote
Apr 11, 2003, 06:29 PM
 
Depending on how your app is structured, perhaps you could use notifications. NSNotificationCenter allows one object to broadcast a message, which is then picked up by all objects that have registered to listen for it. This is nice because the broadcasting and receiving objects don't have to be aware of each other.
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 11, 2003, 06:31 PM
 
Originally posted by wadesworld:
1) Have the objects all (or mostly) know about each other. As described above, this may be the most direct solution, but it quickly becomes unmanageable.
A big problem with this approach is that it can become difficult to keep track of who "owns" an object. If you're using retain/release, like in Cocoa, you can wind up with object A retaining object B, which retains object A. Neither ever get released.

If you're using raw pointers, you can get leaks or danglers pretty easily.
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
Gul Banana
Mac Elite
Join Date: May 2002
Status: Offline
Reply With Quote
Apr 12, 2003, 12:17 AM
 
What I'd do in your situation is have just one class for the controller and delegates. The text-handling class sounds like a good candidate for a singleton, too.
[vash:~] banana% killall killall
Terminated
     
Crusoe
Mac Enthusiast
Join Date: Mar 2003
Location: Globetrotting
Status: Offline
Reply With Quote
Apr 14, 2003, 09:51 AM
 
Can't he use Categories to group class communication methods from different classes or implement a Protocol that returns the object he needs?
Pehaps a protocol that each object defines to return itself? Kind of like a singleton I suppose.

Just getting started with MacDev and ObjC hence the ?s.
If a group of mimes are miming a forest and one falls down, does he make a sound?
     
Gametes  (op)
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status: Offline
Reply With Quote
Apr 19, 2003, 12:00 AM
 
No, now I'm definitely confused, as Apple's sample sketch app seems to be doing just this.

The class SKTDrawAppDelegate has NO connections in IB, and NO variables declared in it's interface, only methods.
But then in it's implementation, it does this:
Code:
- (IBAction)showToolPaletteAction: (id)sender { [[SKTToolPaletteController sharedToolPaletteController] showWindow:sender]; }
Now, excuse me, but how does SKTDrawAppDelegate even KNOW about SKTToolPaletteController???!!!
They are not linked at all!

This is what I'm missing, and I'd seriously appreciate someone telling me how to "cheat" like this
( Last edited by Gametes; Apr 19, 2003 at 12:17 PM. )
you are not your signature
     
itai195
Addicted to MacNN
Join Date: May 2001
Location: Cupertino, CA
Status: Offline
Reply With Quote
Apr 19, 2003, 02:19 PM
 
Gametes -- I believe that is a singleton. If you look up the sharedToolPaletteController method in SKTToolPaletteController, you'll see that it's a class method. All SKTDrawAppDelegate needs to know about is the SKTToolPaletteController class. It doesn't have to have information about any particular instance, it just uses the shared instance. This is the same way NSNotificationCenter works, for example. Singletons are a nice way to prevent your objects from having to know about each other.
     
eno
Banned
Join Date: Sep 2000
Location: Fightclub
Status: Offline
Reply With Quote
Apr 20, 2003, 11:49 AM
 
Originally posted by Gametes:
*sigh* ya I've read those docs.
My advice: give up on Cocoa programming.

Perhaps something like REALBasic would be more your cup of tea?

http://realbasic.com/
     
Gul Banana
Mac Elite
Join Date: May 2002
Status: Offline
Reply With Quote
Apr 20, 2003, 11:54 AM
 
eno, a basic rule everybody's mother told them: If you haven't got anything good to say, then don't say anything at all.
[vash:~] banana% killall killall
Terminated
     
macmike42
Senior User
Join Date: Dec 2001
Status: Offline
Reply With Quote
Apr 20, 2003, 08:22 PM
 
Yeah eno, back up the animosity a bit.

Gametes, what Apple's Sketch.app is doing is using a singleton, which others have explained before. That means that there only ever needs to be one of those objects, so it gets instantiated when it is first requested, and then always returns that same object when you call [SomeObject sharedInstance].

Without using variables, this might seem confusing. Basically there are two types of methods in Objective-C: instance methods and class methods.

Instance methods start with - (minus) and can only be sent to already existing instances of an object. In instance methods, the "self" variable refers to the specific instance of the object whose method was called.

Class methods start with + (plus) and can only be sent to a "class object". One class object per class is created automatically by the Objective-C runtime before any of your code starts to run. In a class method, the "self" variable refers to the class object itself, not an instance of the class. For example, "NSObject" is not only a class, but a class object (incidentally of the C type "Class"). One of the class methods that the NSObject class object can respond to is "alloc". That is why [[NSObject alloc] init] works. "alloc" is a class method and "init" is an instance method. Also, NSDate has a class method called "date", and this is why [NSDate date] returns the exact date at the time of the call.

I hope this helps clear things up a bit instead the other way around.
"Think Different. Like The Rest Of Us."

iBook G4/1.2GHz | 1.25GB | 60GB | Mac OS X 10.4.2
Athlon XP 2500+/1.83GHz | 1GB PC3200 | 120GB | Windows XP
     
IamBob
Senior User
Join Date: Nov 2000
Status: Offline
Reply With Quote
Apr 20, 2003, 10:14 PM
 
Maybe a stripped-down example of a singleton is in order?...

Code:
static id sharedInstance; @implementation YourController + (YourController *)sharedInstance { if (!sharedInstance) sharedInstance = [[YourController alloc] init]; return sharedInstance; } - (id)init { [super init]; if (!sharedInstance) sharedInstance = self; return self; } // Other methods... - (void)passOnFoo { [someObject foo]; } @end // from basically anywhere... [[YourController sharedInstance] passOnFoo];
HTH!
     
Gametes  (op)
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status: Offline
Reply With Quote
Apr 22, 2003, 04:42 PM
 
No I get it now. It wasn't until after I posted the method when someone fully defined a singleton that I realized what they all meant. I don't recall reading that in the literature; I must have skimmed over it before.
I understand class methods, and so I understand what all this was that was causing so much trouble before.
Singleton. hmmm.

Thanks all (except eno)!
you are not your signature
     
itai195
Addicted to MacNN
Join Date: May 2001
Location: Cupertino, CA
Status: Offline
Reply With Quote
Apr 22, 2003, 05:52 PM
 
Glad it's sorted out for you now. It's so cliche to recommend this book, but if you want to know about other OOP design patterns, such as Singletons, check this out. Personally, I think Cocoa is much easier to understand if you understand why it's using singletons, delegates, etc.
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 22, 2003, 05:56 PM
 
Originally posted by IamBob:
Maybe a stripped-down example of a singleton is in order?...

[snip]

You can skip the assignment to sharedInstance in the 'init" method.
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
IamBob
Senior User
Join Date: Nov 2000
Status: Offline
Reply With Quote
Apr 23, 2003, 12:35 AM
 
This should be a bit better..

Code:
static id sharedInstance; @implementation YourController + (YourController *)sharedInstance { if (!sharedInstance) sharedInstance = [[YourController alloc] init]; return sharedInstance; } - (id)init { [super init]; if (sharedInstance) return sharedInstance; return self; } // Other methods... - (void)passOnFoo { [someObject foo]; } @end
Now you can only ever have a single instance of 'YourController' (missed that before) and I took out the pointless assignment. Thanks for pointing that out.
     
eno
Banned
Join Date: Sep 2000
Location: Fightclub
Status: Offline
Reply With Quote
Apr 29, 2003, 02:09 AM
 
Your init method is wrong:

[super init];

if (sharedInstance) return sharedInstance;

return self;
As it stands, someone could just do a [[YourController alloc] init] repeatedly and you'd be leaking, even though you keep on returning the sharedInstance.

Sure, somone might not do that.... but they shouldn't be able to. The code is not robust.

Hint: must override allocWithZone as well...

You gotta love the "advice" that gets dispensed around here!
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 29, 2003, 03:03 AM
 
How 'bout this one...
Code:
static YourController* gSharedInstance = nil; + (YourController *)sharedInstance { if (gSharedInstance == nil) gSharedInstance = [[YourController alloc] init]; NSParameterAssert( gSharedInstance != nil ); return gSharedInstance; } - (YourController *)init { if (self = [super init]) { // do whatever you need to do here } return self; }
To obtain an instance, just do
YourController *instance = [YourController sharedInstance];

When you're done with the instance, just let it fall out of scope - no need to release it or anything.

If you wanted to be really trixty, you could give YourController its own special private init* method, defined in a category in the implementation file. Thus, only the +sharedInstance method knows about the private init method, and only it can call it. The normal init method would log an error and exit. But, you'd just be protecting yourself from yourself if you did this, so why bother. Just do it like in the above example.
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
eno
Banned
Join Date: Sep 2000
Location: Fightclub
Status: Offline
Reply With Quote
Apr 29, 2003, 09:17 AM
 
Originally posted by smeger:
How 'bout this one...
Code:
static YourController* gSharedInstance = nil; + (YourController *)sharedInstance { if (gSharedInstance == nil) gSharedInstance = [[YourController alloc] init]; NSParameterAssert( gSharedInstance != nil ); return gSharedInstance; } - (YourController *)init { if (self = [super init]) { // do whatever you need to do here } return self; }
To obtain an instance, just do
YourController *instance = [YourController sharedInstance];
Doesn't look robust to me.

What's to stop me from just doing:

id singleton = [[YourController alloc] init];

id doubleton = [[YourController alloc] init];

if (singleton != doubleton)
NSLog(@"I've failed to implement a true singleton!");
The above code will print out, "I've failed to implement a true singleton!"
     
absmiths
Mac Elite
Join Date: Sep 2000
Location: Edmond, OK USA
Status: Offline
Reply With Quote
Apr 29, 2003, 12:58 PM
 
Originally posted by eno:
Doesn't look robust to me.

What's to stop me from just doing:



The above code will print out, "I've failed to implement a true singleton!"
Have you got something to prove here? Why are you being so catty - why not just provide your solution rather than bash what others post?

At any rate, I never put application code into the GUI. I generally create a framework to do what I need and implement the UI in terms of that, which simplifies the UI a lot and makes the application more generally useful (like for example when I inevitably have to create a command-line version).

Having all classes be accessible to all other classes is not only difficult but undesirable. The more connections your objects have the more resistant to change they will be. An object should only have connections to objects it needs to perform it's tasks and no more.

Event broadcasters are generally useful for setting up one-way contracts between objects which provide a good deal of flexibility (not to mention that objects generally deliver pertinent objects in the event so that takes care of one more connection).
     
Ghoser777
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status: Offline
Reply With Quote
Apr 29, 2003, 02:42 PM
 
Oh yeah? I'll give you a singularity!

Code:
static MFController* sharedControl = nil; + (MFController *)sharedInstance { if (sharedControl == nil) sharedControl = [[MFController alloc] init]; NSParameterAssert( gSharedInstance != nil ); return gSharedInstance; } - (MFController *)init { //right here I'm not sure if you can access class variables from //an instance method. I'd assume you could. If not, then I'd //just set up a class method in a private category called //controlPointer: which just returns the current sharedInstance //but doesn't create it if it doesn't exist already. if(sharedControl != nil) { //raise all hell with an exception } else if (self = [super init]) { // do whatever you need to do here } return self; }
On the other hand, you may not want to have a singelton be the only possible instance. It's possible that you want to have a global instance of a class, and then some subclasses that aren't so global (aka you instantiate them via alloc, init) because you want distinct subclass objects.

By the way, you could also set up delegate methods or use NSNotification's to communicate between objects. But I think singletons are a pretty good thing to use.

Matt Fahrenbacher
     
itai195
Addicted to MacNN
Join Date: May 2001
Location: Cupertino, CA
Status: Offline
Reply With Quote
Apr 29, 2003, 04:08 PM
 
Well if we're going to be picky, most (maybe all?) of the singleton code provided thus far is not particularly thread safe.
     
smeger
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status: Offline
Reply With Quote
Apr 29, 2003, 08:56 PM
 
Originally posted by eno:
Doesn't look robust to me.

What's to stop me from just doing:

[snip]

As I said, you could...

If you wanted to be really trixty, you could give YourController its own special private init* method, defined in a category in the implementation file. Thus, only the +sharedInstance method knows about the private init method, and only it can call it. The normal init method would log an error and exit. But, you'd just be protecting yourself from yourself if you did this, so why bother. Just do it like in the above example.
Geekspiff - generating spiffdiddlee software since before you began paying attention.
     
IamBob
Senior User
Join Date: Nov 2000
Status: Offline
Reply With Quote
Apr 30, 2003, 03:25 PM
 
static MFController* sharedControl = nil; // ...
Before I realized who posted that I thought the "MF" prefix stood for My Fscking.

     
Brass
Professional Poster
Join Date: Nov 2000
Location: Tasmania, Australia
Status: Offline
Reply With Quote
Apr 30, 2003, 09:36 PM
 
Back to the original topic though...

Does anyone here use a strict Model View Controller (MVC) paradigm in their programming?

According to that paradigm, only the one Controller object has any interaction with the GUI objects ("View"). Everything else, (eg, the model objects) must go through the controller.

I usually do things in strict MVC, and I find it works nicely. This means that the controller is always the delegate of any GUI objects.

Does anyone else do things this way, or is it just me?
     
Catfish_Man
Mac Elite
Join Date: Aug 2001
Status: Offline
Reply With Quote
May 4, 2003, 08:05 PM
 
Originally posted by Brass:
Back to the original topic though...

Does anyone here use a strict Model View Controller (MVC) paradigm in their programming?

According to that paradigm, only the one Controller object has any interaction with the GUI objects ("View"). Everything else, (eg, the model objects) must go through the controller.

I usually do things in strict MVC, and I find it works nicely. This means that the controller is always the delegate of any GUI objects.

Does anyone else do things this way, or is it just me?
I'm working on a simple java database using MVC. It works quite nicely (the paradigm, not the database. The database is only partly done, and somewhat broken).
     
   
 
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Top
Privacy Policy
All times are GMT -4. The time now is 10:20 AM.
All contents of these forums © 1995-2017 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.8 © 2000-2017, Jelsoft Enterprises Ltd.,