views:

184

answers:

5

I have a problem that I solved using delegates, but now I am thinking I may have made a mistake.

This is what I want to do.

I have a class that runs on a delay. When it is done it has a finished delegate that it calls.

Now I have the main class that creates two of these delay classes.

I don't want them to both be handled by the same isfinished method in the main class. I want to use two different ones.

However I believe with the protocol method of creating delegates that this will not work for me.

Is there a way around this?

delayclass setdelegates MainclassFunction1
delayclass setdelegates MainclassFunction2
+5  A: 

If I understand you correctly, take a look at the NSTableViewDelegate protocol. There, each delegate method's first argument is the NSTableView instance sending the message.

You can solve your issue by changing your delegate methods to have your delegating object send itself as an argument. Then, in your delegate, you'd do something like this:

if (theDelegator == objectA)
{
    // Do something
}

if (theDelegator == objectB)
{
    // Do something else
}

This way, you've got one cleanly-implemented delegate method that can handle multiple objects delegating to it.

Joshua Nozzi
+1  A: 

As mentioned, commonly delegate methods would include the object initiating the callback, so you can differentiate that way. Alternately you could have the object post a notification instead, which will also make the originator available.

Ciarán Walsh
A: 

Why are you not just using NSTimer, adding different timers and having them call whatever selectors you like in the class you are using as a delegate now?

Something like:

NSTimer *timer1 = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(myMethod1:) userInfo:nil repeats:YES];

NSTimer *timer2 = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(myMethod2:) userInfo:nil repeats:YES];

Where your methods are:

- (void) myMethod1:(NSTimer*)theTimer
{
  // do Something
}

- (void) myMethod2:(NSTimer*)theTimer
{
  // do Something different
}

You want to save off and retain both timer1/timer2 references, so that you can stop the timers in dealloc ([timer1 invalidate]).

Kendall Helmstetter Gelner
The actual example is much more complicated and I just wanted to abstract it all
Mel
+1  A: 

Using delegates doesn't seem like the correct approach to me; they're generally used for augmenting behavior. What sounds most appropriate here is the target/selector pattern, like NSTimer.

@interface MyObject : NSObject {
@private
    id target;
    SEL selector;
}
@property(assign) id target;
@property SEL selector; /* The selector must return void and accept one argument, which is the MyObject instance that invoked the method. */
@end

@implementation MyObject
- (void)notifyTarget {
    [[self target] performSelector:[self selector] withObject:self];
}
@synthesize target;
@synthesize selector;
@end

This is generally the cleanest approach since the delegate callback doesn't need to disambiguate the sender. Using notifications seems like too much overhead for a problem in this domain.

caleb
Exactly what I needed. Thanks!
Mel
A: 

Short note: Generally, it's bad style to have "if" statements that switch on an object. We all do it occasionally for getting that second list w/o needing a new controller, but switching is what method calls do internally, so ideally you'd just let the ObjC runtime take care of doing the right thing. Several options:

-(void)   tableViewSelectionDidChange: (NSTableView*)theView
{
    SEL theAction = NSSelectorFromString( [NSString stringWithFormat: @"tableView%@SelectionDidChange:", [theView autosaveName]] );
    [self performSelector: theAction withObject: theView];
}

-(void) tableViewUKSourceListSelectionDidChange: (NSTableView*)theView
{
    // UKSourceList-table-specific stuff here.
}


-(void) tableViewUKUsersListSelectionDidChange: (NSTableView*)theView
{
    // UKUsersList-table-specific stuff here.
}

This works best when you have a non-localized string label, like the autoSave name, but can also use the tag, although that makes the code less readable (which one is "table 1"?). Sometimes it's better to just write a subclass that has a special string for that purpose, or even has methods where you can specify selector names to forward the delegate methods to.

Caleb's suggestion is also good, it's also called "target/action" in case you want to google for it. I have several (Mac) classes that have a regular "action" for clicks, a "doubleAction" for double clicks etc.

uliwitness