Question

using xCode 5 with ARC, Objective-C

I have simple program, where I add additional class with protocol for new delegate (very simple).

ArrayGenerator.h

#import <Foundation/Foundation.h>
@protocol ArrayGeneratorDelegate <NSObject>
@required
-(void)StartTask:(NSMutableArray*)array;
@end

@interface ArrayGenerator : NSObject
@property (nonatomic, weak) id <ArrayGeneratorDelegate> delegate;
-(void)ArrayGenerator;
@end

ArrayGenerator.m

#import "ArrayGenerator.h"
@implementation ArrayGenerator

-(void) ArrayGenerator{
//create selector for method in Protocol
SEL mySelector = @selector(StartTask:); 
if (self.delegate && [self.delegate respondsToSelector:@selector(StartTask:) ] ){   
    //call to method    
    [self performSelector:mySelector withObject:array afterDelay:1];
}
@end

and

in ViewController.h I add

#import "ArrayGenerator.h"
@interface ViewController : UIViewController <ArrayGeneratorDelegate>
@end

in ViewController.m I add

 ...
 - (void)viewDidLoad
{
[super viewDidLoad];
ArrayGenerator *ag = [[ArrayGenerator alloc ]init];
ag.delegate = self;
[ag ArrayGenerator];
}
...
-(void)StartTask:(NSMutableArray*)array{
NSLog( @"StartTask" );
}

So I achieve, that after running app in 1 second in Log i could see "StartTask", but instead of this i simply got Exception like

DelegatesWithDelay[2240:90b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ArrayGenerator StartTask:]: unrecognized selector sent to instance 0x8b55200'

enter image description here

Spend a lot of time to find something similar problem with described solution (here and other sites, but nothing from that not help's).

Also find an alternative solution: instead of [self performSelector:mySelector withObject:array afterDelay:1]; I call to [NSTimer scheduledTimerWithTimeInterval:3.0 target:self.delegate selector:mySelector userInfo:nil repeats:NO]; - and all it's work fine, but I want to know why first variant with performSelector:withObject:afterDelay: not work??? (Question)

enter image description here

Also try to:

  • recreate project - almost different - not help -same problem with this method, but with NSTimer - al works;
  • change @property attributs from (nonatomic, weak), to (nonatomic, release) (as was recommended in some solution to similars problem - not help
  • try to use another variants of performSelector methods - not helps
  • try to change mySelector to @selector(StartTask:) - not helps

and so on....nothing help, maybe i miss something?

Was it helpful?

Solution

It should be this:

if (self.delegate && [self.delegate respondsToSelector:@selector(StartTask:) ] ){     
     NSInteger delay = 1;
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [self.delegate performSelector:mySelector withObject:array];
     });
}

Your self (ArrayGenerator) has no selector StartTask, but your delegate does.

OTHER TIPS

Finally I found real reason for this exception (that described in question).

The method performSelector:withObject:afterDelay: is defined on NSObject - but id works for more than just NSObject (so i must to be more specific than just 'id').

What need to change -

@interface ArrayGenerator : NSObject
@property (nonatomic, weak) id <ArrayGeneratorDelegate> delegate;
-(void)ArrayGenerator;
@end

to

@interface ArrayGenerator : NSObject
@property (nonatomic, weak) NSObject <ArrayGeneratorDelegate> delegate;
-(void)ArrayGenerator;
@end

Actually answer found here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top