Int or NSInteger as object for method argument. Objective-C
Asked Answered
E

4

14

I'm having some trouble passing a number as an argument for a method:

- (void)meth2:(int)next_int;

And to call that method I need this:

int next_int = 1;
[self performSelectorOnMainThread:@selector(meth2:) withObject:next_int waitUntilDone:NO];
//update next_int and call meth2 again

at this point, I get a "pointer from integer without a cast" error and would happen the same with a NSInteger. An NSNumber is not useful because it's immutable and I need to change the value constantly. Any idea how can I do this?

Thanks.

Endolymph answered 28/3, 2010 at 21:25 Comment(1)
I think AnthonyF's answer is the only correct answer that works and does not need to change argument types of the method.Soilure
D
23

If you're just trying to call the method, you could use the standard syntax:

[self meth2:next_int];

If you really need to use the performSelectorOnMainThread: you could wrap the number in an NSNumber for the call. You say you can't do this because you need to change the number, but you can just pull an int out and change that:

[self performSelectorOnMainThread:@selector(meth2:) withObject:[NSNumber numberWithInt:next_int] waitUntilDone:NO];
// ... later ...
- (void)meth2:(NSNumber *)number {
  int myInt = [number intValue];
  // do stuff with myInt
}

But maybe you mean that you want to get the value of the number as an output from your call to meth2. If that's what you mean, then you could pass in a double pointer so you can receive a new object back:

- (void)meth2:(NSNumber **)number {
  int myInt = [*number intValue];
  // do stuff with myInt
  *number = [NSNumber numberWithInt:myInt];
}
// The caller can now operate like this:
NSNumber *number = [NSNumber numberWithInt:next_int];
[self performSelectorOnMainThread:@selector(meth2:) withObject:&number waitUntilDone:YES];
int returnInt = [*number intValue];

Of course, that's not really thread-safe, so if you're doing stuff with multiple threads, I would advise using the @synchronized keyword for access to multi-thread-accessed variables, or setting up atomic properties (i.e. properties not declared as nonatomic).

Also, meth is bad for you!! haha

Delbert answered 28/3, 2010 at 21:41 Comment(1)
Hi Tyler, I'm not sure about the @synchronized keyword, i'll read about, but since this integer variable is used as an 'output' from the thread there's no need to worry about concurrency and stuff. The ..withObject:[NSNumber numberWithInt:next_int].. works great, the (NSNumber **) gives me an incompatible pointer type warning. I'll keep in mind that about meth... thanks!Endolymph
P
6

Wrap the integer in an NSNumber before passing it:

int next_int = 1
NSNumber *theNumber = [NSNumber numberWithInt:next_int];
[self performSelectorOnMainThread:@selector(meth2:) withObject:theNumber waitUntilDone:NO];

Then your -meth2: method could look something like this:

- (void)meth2:(NSNumber*)theNumber
{
    int next_int = [theNumber intValue];
    // do whatever
}
Pyrex answered 28/3, 2010 at 21:32 Comment(0)
Z
4

It's a bit of a hack, but this works under ARC:

int next_int = 1;
[self performSelectorOnMainThread:@selector(meth2:) 
                       withObject:(__bridge id)(void*)next_int 
                    waitUntilDone:NO];

The __bridge keyword will tell the compiler to ignore reference counting under ARC, but it requires a pointer, so you first have to cast the int to a C style void pointer. When your method receives the message it will treat that object pointer as if it's an integer.

Note: If you can change the method to take an NSNumber instead of an integer, then that would be the "proper" fix. Unfortunately that's not always possible.

Zilvia answered 23/5, 2014 at 20:30 Comment(2)
This is a nice trick if you want to pass an enum, such as when setting an enum property; eg [cell performSelector:@selector(setSortOrder:) withObject:(__bridge id)(void*)order];Diomedes
I supplement your answer https://mcmap.net/q/827828/-how-do-you-convert-an-argument-passed-to-performselector-withobject-back-from-type-idSoilure
D
2

You can't use next_int as the withObject: because it's not an Object.

Change your call to:

[self performSelectorOnMainThread:@selector(meth2:) 
      withObject:[NSNumber numberWithInt:next_int] waitUntilDone:NO];

EDIT: And change meth2 to expect an NSNumber instead of an int.

Denby answered 28/3, 2010 at 21:32 Comment(1)
That will cause a run-time crash because you also need to modify the method signature to take an NSNumberTurgescent

© 2022 - 2024 — McMap. All rights reserved.