NSInvocation returns value but makes app crash with EXC_BAD_ACCESS

梦想的初衷 提交于 2019-11-29 23:06:32

I am guessing you are using ARC?

The problem is with the line [invocation getReturnValue:&resultSet];. getReturnValue: just copies the bytes of the return value into the given memory buffer, regardless of type. It doesn't know or care about memory management if the return type is a retainable object pointer type. Since resultSet is a __strong variable of object pointer type, ARC assumes that any value that has been put into the variable has been retained, and thus will release it when it goes out of scope. That is not true in this case, so it crashes. (Also, the array that you had resultSet originally point to will be leaked, since getReturnValue: overwrites that value without releasing it. Why you even made that variable point to an object in the first place is beyond me.)

The solution is that you must give a pointer to a non-retained type to getReturnValue:. Either:

NSArray * __unsafe_unretained tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = tempResultSet;

or:

void *tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = (__bridge NSArray *)tempResultSet;

Yes, that's just happenedIn the ARC。

I guess this is the system Bug.

For example:
【iPhone4s + iOS8.4】、【 iphone 4 + iOS7.1】 (crash),
【iPhone6 + iOS9.3】、【 iphone 5 + iOS8.4.1】 (pass),

my test demo download link https://github.com/leopardpan/IssuesDemo

The original code

NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];

To solve the following

case 1:

void *temp = NULL;   
[invocation invoke];
[invocation getReturnValue:&temp];   
NSArray *resultSet = (__bridge NSArray*)temp; 

case 2:

__weak NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];

case 3:

__autoreleasing NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];

case 4:

__unsafe_unretained NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];

Recommended to use case1, principle should be @newacct said
Welcome to discuss

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