int or NSInteger to NSUInteger for index - objective-c

I'm trying to (in Xcode5) use the 'removeObjectAtIndex' for an 'MutableArray' which takes an NSUInteger but the variable I'm using is an integer so I casted with (NSUInteger *) but I get a warning that says cast to 'NSUInteger *' (aka unsigned long *) from smaller integer type. I have not casted the variable 'second' in the code to keep the warning there but it is also an integer
-(void) moveObjectAtIndex:(NSUInteger *)oldIndex toNewIndex:(NSUInteger *)newIndex{
id *member = [self.array objectAtIndex:*oldIndex];
[self.array removeObjectAtIndex:*oldIndex];
if ((NSInteger)newIndex >=(self.array.count)) {
newIndex--; //i casted newIndex because I got a warning about ordered comparison of NSUInteger with NSInteger (I'm not sure if this is best solution)
}
[self.array insertObject:member atIndex: *newIndex];
}
-(void)moveObjectInArray:(NSMutableArray *)array{
[array moveObjectAtIndex:(NSUInteger *) first toNewIndex:second];
}

Your use of pointers is all wonky. id* should just be id and NSUInteger* should just be NSUInteger — you don't want a pointer to a pointer to an object or a pointer to an integer here.

What's problem for you of using just NSUInteger rather than NSUInteger* ?
-(void) moveObjectAtIndex:(NSUInteger)oldIndex toNewIndex:(NSUInteger)newIndex{
id member = [self.array objectAtIndex:oldIndex]; //Here is id, id* is wrong
[self.array removeObjectAtIndex:oldIndex];
newIndex = newIndex >= self.array.count ? : self.array.count - 1; // Here should be self.array.count - 1, not newIndex-1
newIndex = MIN(_cloudListArray.count, newIndex);
[self.array insertObject:member atIndex:newIndex];
}

In the following statement
if ((NSInteger)newIndex >=(self.array.count))
you are typecasting pointer to NSInteger. It should be
if ((NSInteger)*newIndex >=(self.array.count))
Still, you should be careful with typecasting and be wary of their consequences due to any signed/unsigned conversion or data loss.
Also, in this line
[array moveObjectAtIndex:(NSUInteger *) first toNewIndex:second];
type of first should be NSUInteger * or of same size. Please note that long is 64-bit in 64-bit environment and typecasting as smaller pointer type to larger pointer type will yield undefined behaviour. Same applies to second. One solution is that use temporary variable and then copy back the result.

Related

Objective-C implicit conversion loses integer precision 'NSUInteger' (aka 'unsigned long') to 'int' warning

I'm working through some exercises and have got a warning that states:
Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'int'
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSArray *myColors;
int i;
int count;
myColors = #[#"Red", #"Green", #"Blue", #"Yellow"];
count = myColors.count; // <<< issue warning here
for (i = 0; i < count; i++)
NSLog (#"Element %i = %#", i, [myColors objectAtIndex: i]);
}
return 0;
}
The count method of NSArray returns an NSUInteger, and on the 64-bit OS X platform
NSUInteger is defined as unsigned long, and
unsigned long is a 64-bit unsigned integer.
int is a 32-bit integer.
So int is a "smaller" datatype than NSUInteger, therefore the compiler warning.
See also NSUInteger in the "Foundation Data Types Reference":
When building 32-bit applications, NSUInteger is a 32-bit unsigned
integer. A 64-bit application treats NSUInteger as a 64-bit unsigned
integer.
To fix that compiler warning, you can either declare the local count variable as
NSUInteger count;
or (if you are sure that your array will never contain more than 2^31-1 elements!),
add an explicit cast:
int count = (int)[myColors count];
Contrary to Martin's answer, casting to int (or ignoring the warning) isn't always safe even if you know your array doesn't have more than 2^31-1 elements. Not when compiling for 64-bit.
For example:
NSArray *array = #[#"a", #"b", #"c"];
int i = (int) [array indexOfObject:#"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!
if (i == NSNotFound) {
// thought we'd get here, but we don't
NSLog(#"it's not here");
}
else {
// this is what actually happens
NSLog(#"it's here: %d", i);
// **** crash horribly ****
NSLog(#"the object is %#", array[i]);
}
Change key in Project > Build Setting
"typecheck calls to printf/scanf : NO"
Explanation : [How it works]
Check calls to printf and scanf, etc., to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense.
Hope it work
Other warning
objective c implicit conversion loses integer precision 'NSUInteger' (aka 'unsigned long') to 'int
Change key "implicit conversion to 32Bits Type > Debug > *64 architecture : No"
[caution: It may void other warning of 64 Bits architecture conversion].
Doing the expicit casting to the "int" solves the problem in my case. I had the same issue. So:
int count = (int)[myColors count];

Why would a function defined in the same class be considered undeclared? How to declare it properly?

I'm getting the error "undeclared identifier" on the commented line:
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem{
int i = 0;
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
while(i < sizeOfArray){
if(array[i] == elem){
return TRUE;
}
i++;
}
return FALSE;
}
- (int)getNextUnusedID{
int i = rand()%34;
while ([isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}
return i;
}
I really don't understand why, they are in the same .m file.
Why would that be?
Also, this code:
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
is giving me the warning:
Sizeof on array function will return Sizeof 'NSInteger *' (aka: 'int *') instead of 'NSInteger[]'"
How should I properly determine the size of an array?
It looks like you've missed out self from this line
while ([isInIntArray:idsUsed theElem:i])
This should be:
while ([self isInIntArray:idsUsed theElem:i])
As #CaptainRedmuff pointed out, you are missing the target object in method invocation, that is self.
//[object methodParam:x param:y];
[self isInIntArray:idsUsed theElem:i];
To your second Q. In C language you cannot determine the size of an array. That's why they are not used, since we have objects for this. I recommend you to use these:
NSMutableArray *array = [[NSMutableArray alloc] init]; // to create array
array[0] = #42; // to set value at index, `#` creates objects, in this case NSNumber
[array insertObject:#42 atindex:0]; // equivalent to the above
NSInteger integer = array[0].integerValue; // get the value, call integerMethod to get plain int
integer = [[array objectAtIndex:0] integerValue]; // equivalent to the above
[array containsObject:#42]; // test if given object is in the array
[array indexOfObject:#42]; // get index of object from array, NSNotFound if not found
array.count; // to get the number of objects
Important: These arrays have variable size and they are not limited! But you can access elements only at indexes 0..(n-1) (where n in number of objects) and you can set values only for indexes 0..n.
In other words, you can not do array[3] = #42; for empty array, you need to fill first 3 positions first (indexes 0, 1 and 2).
write this in .h file (declare the function)
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem;
and call the method using following way
while ([self isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}

Automatic Reference Counting: Error with fast enumeration

While updating the code below to use Automatic Reference Counting for iOS 5, an error is occurring when the "state->itemPtr" is assigned the buffer when trying to perform Fast Enumeration so that the implementing class can be iterated with the "foreach" loop. The error I am getting is "Assigning '__autoreleasing id *' to '__unsafe_unretained id*' changes retain/release properties of pointer". See the line of code with the comment.
/*
* #see http://cocoawithlove.com/2008/05/implementing-countbyenumeratingwithstat.html
* #see http://www.mikeash.com/pyblog/friday-qa-2010-04-16-implementing-fast-enumeration.html
*/
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (id *)buffer count: (NSUInteger)bufferSize {
NSUInteger arrayIndex = (NSUInteger)state->state;
NSUInteger arraySize = [_tuples count];
NSUInteger bufferIndex = 0;
while ((arrayIndex < arraySize) && (bufferIndex < bufferSize)) {
buffer[bufferIndex] = [_tuples objectAtIndex: arrayIndex];
arrayIndex++;
bufferIndex++;
}
state->state = (unsigned long)arrayIndex;
state->itemsPtr = buffer; // Assigning '__autoreleasing id *' to '__unsafe_unretained id*' changes retain/release properties of pointer
state->mutationsPtr = (unsigned long *)self;
return bufferIndex;
}
The _tuples variable in this example is an instance variable of type NSMutableArray.
How do I resolve this error?
You need to change buffer into __unsafe_unretained:
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id __unsafe_unretained *)buffer
count: (NSUInteger)bufferSize
source
Edit: easy way to get rid of the error in mutationPtr:
state->mutationsPtr = &state->extra[0];
Ziminji,
I had the same problem, which is how I came across this question.
I solved it by keeping the definition of the objects parameter as is (e.g., keeping it as id *) and instead doing a double cast utilizing a void pointer.
So, while this generated errors for me:
state->itemsPtr = (__unsafe_unretained id *)buffer // Error
This worked beautifully:
state->itemsPtr = (__unsafe_unretained id *)(void *)buffer // No error
Disclaimer: I'm not an ARC expert and I can't guarantee you that this won't cause problems with reference counts. However, it appears to work correctly in my testing, and it definitely compiles without warnings.
BTW, I came across this two-part blog entry which covers Fast Enumeration in a nice amount of depth:
Fast Enumeration, Part 1
Fast Enumeration, Part 2
and also this blog entry on __unsafe_unretained:
Unsafe at Any Speed

Simple NSInteger and NSMutableArray question

I'm trying to access an array using another array integer value as an index.
NSInteger index=[appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
int i = index;
questionText.text = [[appDelegate.currentRiddlesContent objectAtIndex:i] objectForKey:#"question"];
//where appDelegate.randomRiddlesCounter is an NSInteger and appDelegate.randomRiddles is a NSMutableArray
However I'm getting incompatible pointer to int conversion warning. How can I fix this above code? The warning I get is coming from the first line.
Try:
NSNumber *index = [appDelegate.randomRiddles objectAtIndex: appDelegate.randomRiddlesCounter];
int i = [index intValue];
questionText.text = [[appDelegate.currentRiddlesContent objectAtIndex: i] objectForKey: #"question"];
NSInteger is an integral type, not an object.
Try this:
int i = [index intValue];
An NSArray like object can only store Objective-C object pointers (i.e. everything that you can assign to an id)
With objectAtIndex you get the object, with indexOfObject:(id)anObject you get the corresponding index.
These two instructions are both valid:
id bla = [appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
NSInteger index = [appDelegate.randomRiddles indexOfObject:myObject];
The second assumes that myObject is at least of type id
So you try to convert a pointer to an int. Therefore the warning is issued.

Require Integer Value not Memory Address whilst avoiding Invalid receiver type compiler warning

I have the following code;
int days = [[SettingsUtils daysToRetainHistory] intValue];
[retainHistory setText:[NSString stringWithFormat:#"Days to retain History: %d", days]];
[daysToRetainHistory setValue:days animated:NO];
where [SettingsUtils daysToRetainHistory] is as follows;
+ (int) daysToRetainHistory {
return (int)[[NSUserDefaults standardUserDefaults] objectForKey:#"CaseBaseDaysToRetainHistory"];
}
I get the compiler warning Invalid receiver type 'int' because I call intValue on an int but unless I do this I can't seem to get the integer value out and always end up with the memory address i.e. 98765432 instead of 9 which ruins the UILabel display [retainHistory] and the UISlider [daysToRetainHistory] value.
How do I avoid the compiler warning and still get my integer value in the label and the necessary float value for setting the UISlider value?
It's because you are casting a memory address to an int that int value isn't working. Instead just use the method you want from NSUserDefaults:
+ (NSInteger)daysToRetainHistory
{
return [[NSUserDefaults standardUserDefaults] integerForKey:#"CaseBaseDaysToRetainHistory"];
}
then just use it directly:
NSInteger days = [SettingsUtils daysToRetainHistory];
You should also store your days with the same method:
[[NSUserDefaults standardUserDefaults] setInteger:days forKey:#"CaseBaseDaysToRetainHistory"];
Although if you set the NSNumber object and it actually does contain an integer, that will work fine too.