-2

In order to understand IMP, I wrote some test codes and found a problem in the process of testing.

enter image description here

I got a surprise

enter image description here

enter image description here

Here is the code.

@interface Test : NSObject

@property (nonatomic, copy) NSString *name;

@end

@implementation Test

- (NSString *)description{
    return [[super description] stringByAppendingString:self.name];
}

- (void)dealloc{
    NSLog(@"Test dealloc %@",self);
}

- (void)test:(NSString *)str{
    NSLog(@"- (void)test  %@",str);
}

+ (void)test:(NSString *)str{
    NSLog(@"+ (void)test  %@",str);
}

- (void)test{
    NSLog(@"- (void)test");
}

+ (void)test{
    NSLog(@"+ (void)test");
}

@end

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
//    IMP imp = [[Test new] methodForSelector:@selector(test:)];
//    NSLog(@"%p",imp);
//    IMP imp1 = [Test instanceMethodForSelector:@selector(test)];
    IMP imp2 = [Test methodForSelector:@selector(test:)];
//    NSLog(@"%p",imp2);
    imp2();
    NSLog(@"%p",imp2);
//    imp2 = [Test methodForSelector:@selector(test)];
//    imp2();
//    imp();
//    imp = [[Test new] methodForSelector:@selector(test:)];
//    NSLog(@"%p",imp);
//    imp();
//    imp1();
//    imp1();
//    imp2();
//    imp2();
//    void (*func)(id,SEL,NSString *) = (void *)imp;
//    func([Test class],@selector(test:),@"");
//    void (*func1)(id,SEL,NSString *) = (void *)imp1;
//    func1([Test class],@selector(test:),@"ha");
//    void (*func2)(id,SEL,NSString *) = (void *)imp2;
//    func2([Test class],@selector(test:),@"haha");
    // Do any additional setup after loading the view, typically from a nib.
}

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

There's no problem when I run a single IMP.But when I run more than one IMP will crash for BAC_ACCESS and it only happens with the function which has arguments.So,why it can work with one and crash with two.

xuanpf
  • 25
  • 3
  • 2
    Please don't post pictures of code. It is very hard to read and we have to retype the entire thing in order to experiment. Post the text instead. I realize you're showing screenshots of the IDE\ debugger, but we really need the text. – zwol Oct 25 '17 at 12:04
  • This is undefined behaviour; your program may crash, or may just continue to run in an invalid state. You need to pass the correct arguments to the function calls (receiver + selector + method args). – Hamish Oct 25 '17 at 12:30
  • This is conceptually a dupe of this question/answer. https://stackoverflow.com/questions/14305191/what-was-the-second-parameter-in-id-impid-sel-used-for – bbum Oct 25 '17 at 23:50

1 Answers1

0

Of course you have a crash, because you need path id, SEL and also NSString * where needed. Better cast to actual function prototype to have compiler errors when you call it wrong, instead of using direct IMP variables. Apple should forbid () operator for IMPs and declare is as void * instead. But people rarely use IMP for direct method calls, so there is no complains.

Cy-4AH
  • 4,370
  • 2
  • 15
  • 22
  • I know this usage is not correct,i want to know why this `IMP` can work once and crash with the second usage.I think it's should be work always or crash always. – xuanpf Oct 26 '17 at 07:48
  • @xuanpf, all is get wrong after first call already, but CPU doesn't know about it eat. You will get crash some where in other place any way and will not understand why. You get undefined behaviour as Hamish said before, because IMP doesn't know actual function prototype and handle objects in call stack wrong. – Cy-4AH Oct 26 '17 at 08:20