0

I'm trying to use the AppDelegate to trigger a delegate method in the viewcontroller via and NSTimer. So in the AppDelegate, I basically have:

AppDelegate.h

@protocol TestDelegate <NSObject>

-(void)testFunction:(NSString *)testString;

@end

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) id<TestDelegate> testDelegate;
...
@end

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    [self.window makeKeyAndVisible];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                  target:self
                                                selector:@selector(trigger:)
                                                userInfo:nil
                                                 repeats:YES];
    return YES;
}

-(void)trigger:(id)sender {
   [self.testDelegate testFunction:self];
}

In my view controller I have:

ViewController.h

@interface ViewController : UIViewController <TestDelegate>
    @property (nonatomic, strong) AppDelegate *appDelegate;
@end

ViewController.m

@implementation ViewController
   ...
   -(void)viewDidLoad {
       self.appDelegate = [[UIApplication sharedApplication] delegate];
       self.appDelegate.testDelegate = self;
   }

   -(void)testfunction:(NSString *)testString {
       NSLog(@"%@", testString);
   }
@end

when I load the ViewController in my app, nothing happens? I know the NSTimer is successfully firing, but the delegate method isn't being triggered.

5
  • Where do you assign anything to testDelegate ? Commented Jan 17, 2014 at 13:22
  • in my appdelegate.h, I have @property (strong, nonatomic) id<TestDelegate> testDelegate; Commented Jan 17, 2014 at 13:25
  • oh i see what you mean... Commented Jan 17, 2014 at 13:26
  • where can I assign the delegate in this example? Commented Jan 17, 2014 at 13:26
  • Whenever you can - you create ViewController and assign it as delegate Commented Jan 17, 2014 at 13:33

4 Answers 4

1

your function declaration is:

-(void)testFunction:(NSString *)testString;

But you call it as:

[self.testDelegate testFunction:self];

so you are sending self to a parameter that is expecting a pointer to an NSString, which is obviously incorrect.

Also, rather than using a timer, I'd use GCD like so:

double delayInSeconds = 10.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    if [self.testDelegate respondsToSelector:@selector(testFunction:)] {
        [self.testDelegate testFunction:@"Test String"];
    }
});
Sign up to request clarification or add additional context in comments.

5 Comments

thanks for the answer, just curious because i haven't gotten a concise answer, but why GCD over NSTimer? What are the drawbacks of using NSTimer?
THe other question is why did the original code compile since there is a protocol defined?
I prefer using a GCD in this case because I'm only firing it once. This way I don't have another property to hold the timer, And I don't have to set up all the code to create the timer either. Also, consider the case where you want the timer to do one thing. You don't need to write a method as the callback, you can write the code in the block, so you can see straight away what the timer will run.
I saw that, but if there is a defined protocol id<TestDelegate> the compiler should have noticed you sending self to testFunction expecting an NSString
Maybe it did. Not everyone pays attention to warnings, though. Although I highly recommend building with 0 warnings - what are we, Windows programmers?
1

Use:

[[UIApplication sharedApplication].testDelegate = self;

instead of all that:

self.appDelegate = [[UIApplication sharedApplication] delegate];
self.appDelegate.testDelegate = self;

Comments

1

Where do you assign your VC as delegate? Is it your VC assigning itself during initialisation/view did load? If you're not doing that I would assign it in ViewDidLoad.

- (void)viewDidLoad
{
     [super viewDidLoad];
     [[UIApplication sharedApplication]delegate].testDelegate = self;
}

Also you would probably want to set the property in AppDelegate weak instead of strong to avoid retaining the VC when/if it is dismissed.

2 Comments

I just added this to viewcontroller viewdidload, but it still doesn't work for some reason?
that should be a question acctually
0

check like

if(!testDelegate) {
   [self.testDelegate testFunction:self];
}

and if your controller is in your navigation controller then loop through and find your controller alive object and assign delegate.

But I would recommended this kinda functionality using LocalNotification

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.