I would use the delegate pattern. Look at some Cocoa classes that have delegates to get the idea of 
the general pattern. Examples: NSTableView, NSControl, NSURLConnection. My app, AppKiDo, provides 
an easy way to list classes that have delegates, and to skim the delegate methods. You could also 
search the Xcode doc window for "delegate methods". I believe there is also documentation 
that specifically discusses the pattern. And Erik Buck's book "Cocoa Design Patterns" 
also discusses it in detail.

Here are the general steps to follow this pattern:

In MyView.h, declare a protocol something like this (typed in Mail, untested):

@protocol MyViewDelegate

- (void)myView:(MyView *)view didMouseDown:(NSEvent *)mouseDownEvent;

@end

Have MyDocument conform to the MyViewDelegate protocol:

@protocol MyViewDelegate;  // Forward declaration of the protocol.

@interface MyDocument : NSDocument <MyViewDelegate>

Add a delegate outlet to your custom view:

@interface MyView : NSView
{
//...
    id <MyViewDelegate> myViewDelegate;
//...
}

// IMPORTANT:
// Declare the delegate property as assign, NOT retain, as delegates are not 
retained in order to avoid retain loops.
@property (readwrite, assign) id <MyViewDelegate>myViewDelegate;

//...
@end

In IB, make the document the delegate of your custom view.

In MyView.m, send a myView:didMouseDown: message to the delegate at whatever 
the appropriate time is. If you're overriding mouseDown:, that's probably the 
right time, something like this:

- (void)mouseDown:(NSEvent *)event
{
    [myViewDelegate myView:self didMouseDown:theEvent];
}

In MyDocument.m, implement the delegate method myView:didMouseDown:.

Note that MyView doesn't have to know that its delegate is a MyDocument. It 
doesn't care. It just knows that the delegate is some object that wants to be 
notified of mouse-down events.

Also note that delegate methods should take the object doing the delegating as their first 
argument, and should use the name of the delegating class (in this case "MyView", hence 
the "myView:" at the beginning of the delegate method). You see this in all Cocoa 
delegate protocols. This is in case you have two MyView instances with the same delegate. The 
delegate can use the first argument to tell which instance it is dealing with. Passing the 
delegating object also allows the delegate method to get further information about it if necessary.

An advantage of the delegate pattern over notifications is that delegate 
methods can have return values. For example, you could have 
myView:didMouseDown: return a BOOL indicating whether it did anything with the 
event. If the superclass of MyView has a non-trivial implementation of 
mouseDown:, you might want to fall back on that behavior by changing the above 
method like this:

- (void)mouseDown:(NSEvent *)event
{
    if (![myViewDelegate myView:self didMouseDown:theEvent])
    {
        [super mouseDown:event];
    }
}

One last variation this pattern: you might want to make some delegate methods 
@optional.

// In MyView.h:
@protocol MyViewDelegate

@optional

- (void)myView:(MyView *)view didMouseDown:(NSEvent *)mouseDownEvent;

@end

// In MyView.m:
- (void)mouseDown:(NSEvent *)event
{
    if ([myViewDelegate respondsToSelector:@selector(myView:didMouseDown:)
        && ![myViewDelegate myView:self didMouseDown:theEvent])
    {
        [super mouseDown:event];
    }
}

I hope this is not too confusing.

--Andy

On Feb 18, 2011, at 02:20 PM, Carlos Eduardo Mello <carloseme...@gmail.com> 
wrote:

Hi Everyone,

I am comming back to cocoa programming and to this list after a few years without programming anything, so please forgive me in advance for any stupid questions. I've read the docs, studied Hillegass's book again and searched the archives, but still couldn't find a definitive answer to my questions.

My app is document-based, started from the XCode template. I have two custom views which are outlets of MyDocument and some extra buttons and text fields on the document's NIB file. Drawing, actions and events work fine for the most part. but in order to do the fun stuff with the app, I need to acess methods in the document as a result of mouse events in the custom views, like updating the values in the text fields and making modifications to my data model classes (the data engine is a collection of crossplatform C++ classes). I came across a few suggestions in cocoa-dev's archives from a few years ago, but they didn't seem quite it.

1. Create outlets in the view's subclasses and point them to MyDocument using IB; 2. Create outlets as in 1., but adding acessor methods to initialize them; 3. accessing MyDocument with messages to the class hierarchy , as in [[[self window] windowController] document];

I tried to use a mix of these approaches, or in other words: query the window controller for the document and then store its reference inside the views forq quicker access. Here's where I get stuck:

In order to use 1. or 2., I need to declare an instance of MyDocument inside my view's classes. The compiler won't let me do this unless I import MyDocument to the class definitions. The problem is that the classes are already included in MyDocument and the "chicken/egg" thing makes XCode spit a zillion compile errors (naturally). I tried declaring the variables inside the custom views as type 'id' and tested the approach calling a MyDocument method which shows some data in various textfields. The code compiled and ran, but MyDocument never got the messages.

// inside custom view's class definition
id document;

// inside awakeFromNib
document = [ [ [ self window ] windowController ] document ];

// inside mouseUp
[document refreshParameters];

If I just query the window controler for the document on demand like this:

[ [ [ [ self window ] windowController ] document refreshParameters ];

the code works, but I still can't get rid of those "message-not-found" warnings:

"warning: no '-refreshParamters' method found
(Messages without a matching method signature will be assumed to return 'id' and accept '...' as arguments.)"

So my questions are:

1) Is there a better way to approach this?
2) Is it OK to just call the document like this and ignore the compiler warning?

I'd really appreciate if someone could comment on this - i'd hate to find out later that i'd been building on a bad design...
Thanks already for a y help.

Carlos.


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/aglee%40mac.com

This email sent to ag...@mac.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to