2

This piece of code used to compile fine in non-ARC:

int *privateObjMemory = (int *)[myObject performSelector:@selector(privateMethod)];

now I am in ARC I get:

Cast of an Objective-C pointer to 'int *' is disallowed with ARC

How could I fix this? :)

nacho4d
  • 43,720
  • 45
  • 157
  • 240

5 Answers5

3

Write it as:

int* privateObjMemory = [myObject privateMethod];

;)

The reason you want to avoid this is that it's ambiguous to ARC. performSelector: returns an object -- should that int* be retained? hmmm... no.

Update

Based on comments, and removing previous writing:

But that's not a very good solution. If you are calling a specific private API, then you must know its signature (e.g. parameter and return types). If it is your private API, then figure out a way to make that private interface visible selectively.

If it is somebody else's private API, then declare a category on the type which has the correct parameters and return type.

Then the selector is declared properly, and the compiler will be able to setup the call correctly by messaging the object directly -- without the need for using performSelector:.

justin
  • 104,054
  • 14
  • 179
  • 226
  • The problem is that privateMethod is not visible so doing `[myObject privateMethod];` triggers: >> `"No visible @interface for MyObject declares the selector privateMethod"`. Because it is private :p – nacho4d Nov 20 '12 at 10:20
  • @nacho4d using an unnamed selector could also cause the warning. since you're clearly beyond the point of safety here =p just declare a category with a correctly typed prototype. if it's your own private API, then just figure out a better way to make that private interface visible *selectively*. those are both much safer than using the `void*` above. – justin Nov 20 '12 at 10:25
  • The API is Appl... ahem ... someone's else. Creating the category seems to work fine. Although I use to do : `if ([myObject respondsToSelector:@selector(privateMethod)]) { ... ` to make sure this hack does not cause a crash. Now, with the new property that clause will be always YES, even if the real implementation does not exist. How can I check `privateMethod` does really exist if I declare the property? – nacho4d Nov 20 '12 at 10:48
  • @nacho4d is it really? did you test it? the faux-declaration should not export a definition, and the `resondsToSelector:` should be tested at runtime. – justin Nov 20 '12 at 11:02
  • your are right.The declaration does not export a definition and now my code works again. It is weird because long time ago I did experienced [obj respondsToSelector:...] returning always YES when declaring a category for that selector, I guess something else was wrong there. Thanks. I learned something today :) – nacho4d Nov 21 '12 at 04:16
2

Don't cast an Obj-C pointer to int *, there's no way around this if using ARC.

The reason it's this way, is because converting a ponter to an int* means at runtime there's no way to keep track of the memory of the object the pointer is pointing to. As such, it was allowed when not using ARC (as you could manage the memory yourself), but not when ARC is active.

If you must do this, then you can disable ARC on the file it's being used in. Use the -fno-objc-arc compiler flag on the implementation file, within Project settings.

enter image description here

WDUK
  • 18,870
  • 3
  • 64
  • 72
  • This will be my last option ... :) I really hope there is a way of doing this with ARC – nacho4d Nov 20 '12 at 10:25
  • I'll reiterate, "Don't cast an Obj-C pointer to int *, there's no way around this if using ARC.". This solution means you can keep your code as-is, so it's a lot less risk, especially when I assume it has been tried and tested in the past ;) – WDUK Nov 20 '12 at 10:28
0

I don't think that this is really linked to ARC. ARC just causes the warning or error. AFAIK (and I do not sign this in blood) the return value of methods invoked with performSelector is either nil or id. Therefore it must be an object not a skalar. It may well work with int* as id is a reference to (but to an object, not to a scalar). To be on the save side you should change your code and return an NSNubmer object instead.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Hermann Klecker
  • 14,039
  • 5
  • 48
  • 71
0

Use id for type of your object.

Dave
  • 1,081
  • 6
  • 10
0

In ARC documentation, they are specifically saying..

There is no casual casting between id and void *.

performSelector returns an id and it can't be casted with a non objective C object reference.

In the documentation I linked, scroll down and read under the section "Managing Toll Free bridging".

Krishnabhadra
  • 34,169
  • 30
  • 118
  • 167