Nilesh Agrawal
Nilesh Agrawal

Reputation: 3042

Objective C Callback on particular event

I am new to objective C and trying to develop my own callback function, the callback function gets called on a particular event like receiving data from network like NSURLprotocol does and once received it will NSLog a message that "Event has Occured" or display as text on UIViewController or any UI related action.

So, I am totally confused as to where the eventOccuredMethod should be called to let the receiveController be called and execute the implementation inside it.

I have used protocols like NSURLProtocol before, but I don't know how to implement them to get such callbacks being called.

Any video links, answers, articles links are welcomed.

//Sample.h file 
#import <Foundation/Foundation.h>
@class Sample;
@protocol SampleProtocol <NSObject>
-(void)receivedCallback;
@end

@interface Sample : NSObject
@property (nonatomic,weak) id<SampleProtocol> delegate;
-(void)eventOccured;
@end

//Sample.m file

#import "Sample.h"

@implementation Sample
-(void)eventOccured{
    if([_delegate conformsToProtocol:@protocol(SampleProtocol)])
    [_delegate receivedCallback];
}
@end

//ViewController.h file

@interface ViewController : UIViewController<SampleProtocol>

@end

//ViewController.m file

#import "ViewController.h"

@interface ViewController (){

    Sample *s;
}

@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    s = [[Sample alloc] init];
    s.delegate = self;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)receivedCallback:(Sample *)sample{
    NSLog(@"Event Has Occured");
}

@end

I am not sure of the following call which I am making ...

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    Sample *s = [[Sample alloc] init];
    [s eventOccured];
}

Upvotes: 1

Views: 454

Answers (4)

Samuel Peter
Samuel Peter

Reputation: 4166

You are implementing the delegate pattern the right way. But if the Sample object doesn't generate its own events but instead is relaying events posted to it from somewhere else, as is the case in your example, you have to ensure that the object which has the ViewController as a delegate and the object that receives the message are in fact the same. One way to do it is to make Sample a singleton :

#import "Sample.h"

@implementation Sample

+ (instancetype)sharedInstance
{
    static id sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[[self class] alloc] init];
    });
    return sharedInstance;
}

-(void)eventOccured{
    if([_delegate conformsToProtocol:@protocol(SampleProtocol)])
        [_delegate receivedCallback];
}

@end

And then in your view controller you would do

s = [Sample sharedInstance];

and in your appDelegate :

[[Sample sharedInstance] eventOccured];

Another way to ensure that you are using the same object, as vikingosegundo pointed out, would be to set the view controller's Sample object from the appDelegate.

For this use case, you could also consider using Notifications.

Upvotes: 1

Simon McLoughlin
Simon McLoughlin

Reputation: 8465

?, i'm very confused. I don't think you understand what you have written. You should never try copy code like this from online without first reading a tutorial to understand what it is you are doing. This can be very dangerous.

Sample.h / .m is a class, this class defines a protocol that says "In order for me to alert you to the fact an event has occurred, you need to implement method X".

This is the "protocol", by conforming to the protocol, another class (lets say a ViewController) is saying that it implements the method that Sample is looking for.

So Sample will run code, and when it wants to pass some info back to the other class (ViewController in this case) it calls one of the methods defined in the protocol.

e.g. (not fully working code)

Sample.m

- (void)getDataFromURL:(NSStirng *)url
{
     [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)
     {
            if([_delegate conformsToProtocol:@protocol(SampleProtocol)])
            {
                 [_delegate receivedCallback];
            }
     }];
}

So when Sample runs the method getDataFromURL it will request its data, when the data returns, Sample will call the method receivedCallback on its delegate. Which in this case is an instance of a viewController.

EDIT

please also note what [_delegate conformsToProtocol:@protocol(SampleProtocol)] does. This asks does the delegate instance conform to the protocol. But this protocol hasn't said that recievedCallback is required. So you have no way of knowing the method is there.

either use:

@protocol SampleProtocol <NSObject>

@required
-(void)receivedCallback;

@end

in the protocol definition or

if(self.delegate && [self.delegate respondsToSelector:@selector(receivedCallback)])

to check is it implemented

Upvotes: 1

Rukshan
Rukshan

Reputation: 8066

You should call EventOccurred within your data retrieving method. Once the data retrieving is complete call EventOccured.

@protocol SampleProtocol <NSObject>
-(void)receivedCallback;
@end

This protocol must be implemented in your data retrieving class. And make sure -(void)receivedCallback; has a parameter to send data to your ViewController

Upvotes: 0

vikingosegundo
vikingosegundo

Reputation: 52227

you are calling eventOccured on a second, independent Sample instance that has now delegate set.

The easiest fix: make the view controller send it to it's sample instance.

better: give the view controller a property that holds sample and sat that from the application delegate.

Upvotes: 0

Related Questions