Crash in objc_retain in method performed with performSelector

后端 未结 1 2113
南旧
南旧 2021-02-20 14:15

I have this strange crash relating to ARC auto-inserting objc_retains in my code.

I have the following two classes:

@interface MenuItem : NSObject
@prope         


        
相关标签:
1条回答
  • 2021-02-20 14:56

    The reason for the crash was because I was using the wrong performSelector.

    NSObject defines multiple versions of performSelector. The one I was invoking was:

    - (id)performSelector:(SEL)aSelector;
    

    However the method I was invoking took an id parameter. Eg:

    - (void)someMethod:(id)sender;
    

    Now ARC being the nice safe memory management system that it is tries to ensure that parameters are properly retained during the execution of a method. So even though my someMethod: was empty ARC was producing code that looked like this:

    - (void)someMethod:(id)sender 
    {
        objc_retain(sender);
        objc_release(sender);
    }
    

    The problem with this however was that I was invoking performSelector: and not supplying a value for the sender parameter. So sender was pointing at random junk on the stack. Therefore when objc_retain() was invoked the app crashed.

    If I change:

    MenuItem *item = [[MenuItem alloc] initWithTarget:widget 
                                              action:@selector(someMethod:) 
                                              object:nil];
    

    to

    MenuItem *item = [[MenuItem alloc] initWithTarget:widget 
                                              action:@selector(someMethod) 
                                              object:nil];
    

    and

    - (void)someMethod:(id)sender;
    

    to

    - (void)someMethod;
    

    Then the crash goes away.

    Similarly I can also change

    [self.target performSelector:self.action];
    

    to

    [self.target performSelector:self.action withObject:nil];
    

    if I want to follow the 'standard' form of target-action methods that take a single parameter. The benefit of the second form of performSelector is that if I'm invoking a method that doesn't take a parameter it will still work fine.

    0 讨论(0)
提交回复
热议问题