Crash in objc_retain in method performed with performSelector

自闭症网瘾萝莉.ら 提交于 2019-12-04 02:58:59
orj

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!