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.
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
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
}
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.
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.
Related
I want to convert NSValue to NSNumber. What is wrong with this code?
char value[4];
[myNSValue getValue:(void*)value];
NSNumber *number = [[NSNumber alloc] initWithBytes:(void*)value objCType:[myNSValue objCType]];
NSTimeInterval duration = [number intValue];
It causes a crash on the last line. What could happen here?
As #ale0xB diagnosed in the comments above, NSNumber doesn't actually provide its own implementation of the -initWithBytes:objCType: method; so, when you invoke that selector, you're actually getting the implementation that comes from NSNumber's base class NSValue. There is no1 difference between [[NSNumber alloc] initWithBytes:foo objCType:bar] and [[NSValue alloc] initWithBytes:foo objCType:bar] — they both call the same method implementation, which releases the self it was given and returns a new object which is generally of type NSConcreteValue (an undocumented subclass of NSValue but not of NSNumber).
To be even clearer:
#import <assert.h>
#import <Foundation/Foundation.h>
int main()
{
id x;
x = [NSNumber numberWithInt:42];
assert( [x isKindOfClass:[NSNumber class]] );
assert( [x respondsToSelector:#selector(intValue)] );
int fortytwo = 42;
x = [[NSNumber alloc] initWithBytes:&fortytwo objCType:#encode(int)];
assert( [x isKindOfClass:[NSValue class]] );
assert( ! [x isKindOfClass:[NSNumber class]] ); // yikes!
assert( ! [x respondsToSelector:#selector(intValue)] ); // your particular problem
}
However, categories to the rescue! Martin Häcker has written a category NSNumber(CreatingFromArbitraryTypes) which can be adapted to do what you want. See the public-domain source code here.2 The basic idea is to special-case every possible type-encoding:
if you're trying to encode an "i", then dispatch to -numberWithInt:;
if you're trying to encode an "f", then dispatch to -numberWithFloat:;
and so on. This is tedious; but once you've written the code once, you can use the category from then on and simply call [NSNumber numberWithValue:myNSValue].
(1 – More or less. There's no difference significant in this context, I'd say.)
(2 – That code has a couple of bugs, especially in later revisions. See my patch here.)
Please read my comment above for further explanation.
To achieve what you want, simply init an NSString with your (char *) and then invoke NSString's intValue. - Assuming you know the type, if not look at the comments below -
Cheers
In which case we need a pointer of a BOOL variable in Objective C language?
I have a code for collapsible UITableView in which there is a function declaration:
- (void)toggle:(BOOL*)isExpanded section:(NSInteger)section;
and its definition is:
- (void)toggle:(BOOL*)isExpanded section:(NSInteger)section
{
*isExpanded = !*isExpanded;
NSArray *paths = [self indexPathsInSection:section];
if (!*isExpanded)
{
[self.tableview deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
}
else
{
[self.tableview insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
}
*isExpanded = !*isExpanded; What is the meaning of this statement as I have never used this kind of statement in case of BOOL Variable.
Following are other two functions of same code which are called in the sequence of above function:
- (NSArray*)indexPathsInSection:(NSInteger)section
{
NSMutableArray *paths = [NSMutableArray array];
NSInteger row;
for ( row = 0; row < [self numberOfRowsInSection:section]; row++ )
{
[paths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
}
return [NSArray arrayWithArray:paths];
}
- (NSInteger)numberOfRowsInSection:(NSInteger)section
{
return [[sectionDataArray objectAtIndex:section] count];
}
sectionDataArray is the array for number of rows in each section. I may be unclear but if you got my point please explain all this.
Here is the link to that code
Thanks
Pointers to variables (or pointer to pointers of objects) are useful, if you want to change their value in another function. If you pass a plain BOOL to a method, you can use it, but if you change it, this change is only local as it was passed by value. If you pass the pointer/address of the variable instead, you can also change its real value.
This comes in handy if you need more than one return value and don't want to wrap it up in an object. It's also a common pattern in Cocoa where NSError variables are passed as pointers, i.e -(BOOL) doSomethingError:(NSError **)error.
It's unclear why you did have to pass the pointer to a BOOL. Even if you were tracking the expanded status of all sections using an array of BOOLs, I would guess setting it up as an instance variable would have been better.
*isExpanded = !*isExpanded;
This is basically flipping the value of the BOOL. Since you've passed a pointer, you will be able to see the flip in the caller method.
As such, the second part indulges itself in building a list of all index paths in a particular section so that the app can delete the section using deleteRowsAtIndexPaths:withRowAnimation: method of UITableView. Somehow using deleteSections:withRowAnimation: method could've been easier. Same thing goes for insert.. methods.
An array of booleans
Assuming that you need to maintain a dynamic array of BOOLs. NSMutableArray is a proper fit.
Say, you start off with a certain number of sections that have expanded set to NO.
/* In the interface of the view controller */
NSMutableArray * expandedStatuses;
#property (nonatomic, retain) NSMutableArray * expandedStatuses;
/* In viewDidLoad or viewWillAppear:, as needed */
self.expandedStatuses = [NSMutableArray array];
for ( int i = 0; i < numberOfSections; i++ ) {
[self.expandedStatuses addObject:[NSNumber numberWithBool:NO]];
}
Later, in your toggle:section: method do this,
/* Getting the expanded status of the section */
BOOL expanded = [[self.expandedStatuses objectAtIndex:section] boolValue];
/* Flipping the expanded status of the section */
[self.expandedStatuses replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:!expanded]];
If you are interested in deleting a particular section,
[self.expandedStatuses removeObjectAtIndex:sectionIndexToDelete];
And if you are interested in adding,
/* Adding at the end */
[self.expandedStatuses addObject:[NSNumber numberWithBool:NO]];
/* Or adding it in between */
[self.expandedStatuses insertObject:[NSNumber numberWithBool:NO] atIndex:sectionIndexToInsertAt];
So NSMutableArray is pretty flexible to play with. You can consider it as an option to switch to.
They are intended to use isExpanded even after the exit of toggle: method with the modified value.
*isExpanded = !*isExpanded;
You could avoid using BOOL pointer in method by declaring isExpanded as the member variable (iVar) pf your class .
And use belwo
isExpanded = !isExpanded;
Instead of using
*isExpanded = !*isExpanded;
You can try using
isExpanded[0] = !isExpanded[0];
BOOL is not class type it is
typedef signed char BOOL;
You can not have pointer to BOOL variable.
i wrote this code :
bs = [NSNumber numberWithFloat:[mystring.text floatValue]];
NSLog(#"bs = %#",bs);
....
float x = [bs floatValue];
when the program want to excute the line above it crash why ?
the output :
bs = 2.8 which true 100%
Between the time you assigned an NSNumber object to your ivar bs it was release by the runtime. I am assuming where you created bs and where you try to assign it to x are in two different methods. If that is the case, you need to tell the runtime you want to keep the ivar bs around for awhile:
[bs retain];
And if you do that, you need to tell the runtime you are done in the dealloc:
-(void)dealloc {
[bs release];
[super dealloc];
}
Basically, if you didn't create an object with alloc, copy, mutableCopy, new in the method name, then you don't own the object.
the code snippet seems ok.
and I guess the reason is bs was released before fetching its float value.
the simplest way to retain bs is to change it to a property:
#property (nonatomic,retain)NSNumber* bs;
and release it in dealloc
I'm trying to change the alignment of a UILabel on the main thread like this
[updateLabel performSelectorOnMainThread:#selector(setTextAlignment:) withObject:UITextAlignmentCenter waitUntilDone:YES];
However this generates a "makes pointer from integer without cast error. What's the correct way to do this?
This is not going to work because UITextAlignmentCenter is not a pointer to an object, but a simple integer. A solution is to implement an own method on the view controller that sets the alignment to center via updateLabel.textAlignment = UITextAlignmentCenter; and calling [yourViewController performSelectorOnMainThread:#selector(setUpdateLabelTextAlignmentToCenter) withObject:nil waitUntilDone:YES];
You're passing a raw integer to "withObject" instead of an object, that's why you're getting the error. Instead, you could call a selector of your own on the main thread that does the job for you, passing in a dictionary or array containing the UILable object to change, and the new alignment value packaged up as a NSNumber:
- (void) changeLabelAlignment:(NSArray *)argsArray
{
UILabel *lbl = [argsArray objectAtIndex:0];
int alignment = [[argsArray objectAtIndex:1] intValue];
lbl.textAlignment = alignment;
}
calling it this way:
...
NSArray *argsArray = [NSArray arrayWithObjects:label, [NSNumber numberWithInt: UITextAlignmentCenter], nil];
[myClassObject performSelectorOnMainThread:#selector(changeLabelAlignment:)
withObject:argsArray
waitUntilDone:YES];
I asked a similar question, but I couldn't get it working exactly. I'm building an iPhone app, and there is a method that I want called from different files. I figured the easiest way would simply be to make a method in another file, and call the method from the other files.
Here are some problems. I need to return multiple values from the method, after passing it multiple values. For example, I'm passing it: (int, int, int, string, string). And it needs to return all of those values, after they have been changed. Someone showed me this code:
- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness
{
varTurns--;
if (varTurns <= 0) {
varFatness = varFatness - 5;
}
else {
varFatness += 2;
}
return [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:varFatness], #"FATNESS", [NSNumber numberWithInt:varTurns], #"TURNS", nil];
}
However, this code doesn't work, and I need some more information to really understand it. Let's assuming I'm passing it these values:
int varMoney;
int varNumSheep;
int varNumShepherds;
NSString *test1;
NSString *test2;
So I need to get all of these values back from the method.
How do I declare this in the header file? This should be in an Objective-C file, but could you give me the code for the entire file so I can see where it would go with the #implementation and #end, whatnot. Also, how would I call this method?
What about passing in the values as pointers?
For example:
- (void) getValuesForInt:(int *)int1 anotherInt:(int *)int2 aBool:(BOOL *)bool1 anotherBool:(BOOL *)bool2 {
if (*int1 == 42 && *int2 == 0) {
*int1 = 0;
*int2 = 42;
}
if (*bool1 == NO) {
*bool2 = YES;
}
}
Then you can invoke it like:
int int1 = 42;
int int2 = 0;
BOOL bool1 = NO;
BOOL bool2 = NO;
[self getValuesForInt:&int1 anotherInt:&int2 aBool:&bool1 anotherBool:&bool2];
NSLog(#"int1: %d int2: %d bool1: %d bool2: %d", int1, int2, bool1, bool2);
//prints "int1: 0 int2: 42 bool1: 0 bool2: 1"
Edit:
This works equally well with objects. You'll often see this used when dealing with NSError objects:
NSError *error = nil;
[anObject doSomething:foo error:&error];
Can be implemented as:
- (void) doSomething:(id)terrible error:(NSError **)error {
if ([terrible isEqual:reallyBad]) {
if (error != nil) { *error = [NSError errorWithDomain:#"domain" code:42 userInfo:nil]; }
}
}
You can use a block closure to pass back multiple values from a method like this. -rrh
[self heyFunctionGiveMeBackTwoValuesFromThisFruitArray:#[#"apple", #"orange", #"banana", #"apple"] findThisFruit:#"apple" closureFunction:^(int fruitCount, NSString* fruitString)
{
NSLog(#"Two values returned, int-fruitCount:%d, NSString-fruiteString:%#", fruitCount, fruitString);
}];
- (void)heyFunctionGiveMeBackTwoValuesFromThisFruitArray:(NSArray*)fruitsArray findThisFruit:(NSString*)findThisFruit closureFunction:(void (^)(int fruitCount, NSString *fruitString))passBackResultsUsingThisClosure
{
NSInteger fruitsFound = 0;
NSString* fruitsMessage = [NSString stringWithFormat:#"No %# Found", findThisFruit];
for (NSString* string in fruitsArray)
{
if ([string compare:findThisFruit] == NSOrderedSame)
{
fruitsFound++;
}
}
if (fruitsFound > 0)
{
fruitsMessage = [NSString stringWithFormat:#"You have %# on your list this many times:%d", findThisFruit, fruitsFound];
}
passBackResultsUsingThisClosure(fruitsFound, fruitsMessage);
}
Results:
Two values returned, int-fruitCount:2, NSString-fruiteString:You have apple on your list this many times:2
If you have that many different things that need to be returned from a method, either encapsulate it into an NSDictionary as others have suggested or consider just defining a class. You can declare the instance variables and properties to encapsulate the data, as needed.
Defining a class to encapsulate such information proves to be quite efficient and maximizes flexibility. If you need to refactor your app such that the collection of data gains new fields, needs to be saved for later, or might need to gain functionality, a class will ease these changes.
Since you can only return a single value from any method in C and C-derived languages, you simply need to return a single value that represents all of your other values. This is what your sample code is doing with an NSDictionary.
The sample code is correct, even if it's a bit contrary to common Objective-C style.
What you declare in the header file is simply the declaration of the method, that is:
#interface MyClass : NSObject
- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness;
#end
In the source file, then:
#implementation MyClass
// code, as given above
#end
If you only need to return primitive values, then returning a struct may be the optimal solution. You get compile-time error checking (e.g. as opposed to an NSDictionary where you could attempt to read an invalid key), while not requiring all the code/files involved in creating a class.
typedef struct myStruct {
int varMoney;
int varNumSheep;
int varNumShepherds;
} myStruct;
Apple uses structs in many of their methods too (e.g. CGPoint, CGRect).
The reason this won't work with objects is because ARC forbids this.
One slight improvement to the last point in some designs is to use a struct holding enum members. This gives you the compile-time checking already mentioned, something that looks like an object in the return value, and the benefit of clear cases if you need to check the values in the return.
The struct:
typedef struct _SIXRecorderStateChange {
SIXRecorderState oldState;
SIXRecorderState newState;
} SIXRecorderStateChange;
The client code:
SIXRecorderStateChange stateChange = [recorderState stop];
if (stateChange.newState == SIXRecorderStopped) {
...
...