0

I want to invoke a delegate in class method.

The example below obviously does not work, since the delegate is an instance variable that is accessed within a class method. (Error: instance variable 'delegate' accessed in class method)

Is there an alertnative?

My header file:

//  MyClass.h

#import <Foundation/Foundation.h>

@protocol MyDelegate <NSObject>

-(void)update;

@end

@interface MyClass : NSObject
{
    id<MyDelegate> delegate;
}
@property (nonatomic, retain) id delegate;

+(void)methodThatInvokesDelegate;
@end

My implementation file:

//  MyClass.m
#import "MyClass.h"

 @implementation MyClass
 @synthesize delegate;

+(void)methodThatInvokesDelegate{
[delegate update];
 }

 @end
steak2002
  • 177
  • 2
  • 11
  • 3
    you're missing the "@" in front of protocol. what exactly is the problem you're seeing? – Mike M May 29 '13 at 11:34
  • @MikeM the above was just an example. Not code that I am actually using. But just to illustrate the problem. I edited my post and added the '@'. The error i': "instance variable 'delegate' accessed in class method – steak2002 May 29 '13 at 11:38
  • Why do you want to do this? Maybe you're better off using a singleton pattern? – Marcel May 29 '13 at 11:39
  • if you want to send a simple "update" to a class, it's maybe enought to use the NSNotificationCenter http://stackoverflow.com/questions/16409448/ios-updating-text-labels-with-nsuserdefault-data-on-different-views/16409612#16409612 . Else I would recommand to set the methode non-static or use a singleton like @Marcel said – geo May 29 '13 at 11:49
  • I want to an event to be triggered within a class method. This event is then subscribed to by another class. – steak2002 May 29 '13 at 11:53

3 Answers3

3

Three obvious options:

  • Singleton
  • Static variable (i.e., class variable) pointing to the delegate
  • Use NSNotification's rather than delegates

Since a singleton (and a static variable) can't keep track of the lifecycle of delegates, I think option three would be the cleanest.

Stephen Darlington
  • 51,577
  • 12
  • 107
  • 152
  • I would not take option 3, because notifications are "untargeted", while delegating is "targeted". With targeted I want to say, that delegating points to a specific object. – Amin Negm-Awad May 29 '13 at 11:55
  • @AminNegm-Awad I take your point but we're trying to do something a bit odd here so there's bound to be some breakage. I would consider notifications to be the lesser of evils in this case. – Stephen Darlington May 29 '13 at 12:03
  • This is a subject of taste for sure. But I think, that a static variable is nothing evil. And with notifications, for example, you will never have a return value. – Amin Negm-Awad May 29 '13 at 12:42
  • Prior to zeroing weak references, a static delegate would be a crash waiting to happen. Static _variables_ in general are fine but I think delegates are a special case -- because they're dependent on but not in control of another object -- even though, technically, they're just a variable like any other. Also, notifications have the user dictionary, so can pass values back. – Stephen Darlington May 29 '13 at 12:57
  • How to pass a value back? And whose value? You can have a mass of notification observers. – Amin Negm-Awad May 29 '13 at 13:30
  • NSNotification has `userInfo` and `object` properties, so you can get notifications about a particular object and data can be returned. As the developer, you are in control of both sides of the interface; there's no _requirement_ to have a mass of observers. – Stephen Darlington May 29 '13 at 14:47
  • Of course, there is no requirement to have more than one observer. But it is *possible* and no observer knows whether there are other observers. Notifications are made for *broadcasting*. This is the reason for their existence. The concept of broadcasting implies, that the broadcasted information is not changed. This would have side effects to all observers. Doing so seems to be highly contra-conceptional. – Amin Negm-Awad May 29 '13 at 15:00
  • And delegates are really designed for objects and not classes. Pick the rule you want to break. Your choice; all the options I list above will work. – Stephen Darlington May 29 '13 at 15:36
  • Class objects are objects and the delegate will be a instance object. But anyway it would not break with an expectation of the developer, who implements the delegate method. The only difference is, that the sender param is a class object. But this is specific to this protocol and documented through the methods in the protocol. No broken expectation. But, yes, I agree and as I said: It's a matter of taste. – Amin Negm-Awad May 29 '13 at 15:54
0

I want to know the context, which let you run in that situation. ;-) Anyway:

First: Delegates are set for a specific instance object. Because of this, you can have different delegates for different instances of the same (delegating) class.

Second: A class method runs inside a class object of that class. This is an object that is different from every instance object of that class. So there is nothing that can be called "the delegate". You can have 100s of delegates.

Third: Your class object needs a delegate at its own. So you have to add a property delegate to the class object and then use this. (Yes, it is possible to have properties an a class object. I did not write declared property.) If you need further information on how to do this, just comment it. I will add code.

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50
0

I'm not sure if this will help you, but I have a similar situation where I have a class method used for data loads. In this case, the class instantiates itself (so that the caller doesn't need to) until it is done. (this code was edited somewhat to make it work here)

header file:

    @protocol DataLoaderDelegate2 <NSObject>
    - (void) dataLoaderSuccess:(NSData *)data loader:(id)theloader;
    - (void) dataLoaderFailed:(NSString *)error loader:(id)theloader;
    @end

    @interface DataLoader2 : NSObject {
            NSURLConnection *conn;
            NSMutableData   *receivedData;
            NSFileHandle    *fileHandle;
            id <DataLoaderDelegate2>    delegate;
    }
    @property (nonatomic, assign) id<DataLoaderDelegate2>delegate;

Call to start the process - the call to initWithRequest passes "self" along.

    + (DataLoader2 *)loadWithURLRequest:(NSURLRequest *)req delegate:(id)_delegate
    {
        DataLoader2 *dl = [[DataLoader2 alloc] init];
        [dl setDelegate:_delegate];
        conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
        return dl;
    }

When the data is done loading, it cleans up with something like

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {

            if ([delegate respondsToSelector:@selector(dataLoaderSuccess:loader:)])
                    [delegate dataLoaderSuccess:(fileHandle)?(id)fileHandle:(id)receivedData loader:self];
            [self autorelease];
    }
Mike M
  • 4,358
  • 1
  • 28
  • 48