Why don't I declare NSInteger with a * - objective-c

I'm trying my hand at the iPhone course from Stanford on iTunes U and I'm a bit confused about pointers. In the first assignment, I tried doing something like this
NSString *processName = [[NSProcessInfo processInfo] processName];
NSInteger *processID = [[NSProcessInfo processInfo] processIdentifier];
Which generated an error, after tinkeing around blindly, I discovered that it was the * in the NSInteger line that was causing the problem.
So I obviously don't understand what's happening. I'll explain how I think it works and perhaps someone would be kind enough to point out the flaw.
Unlike in web development, I now need
to worry about memory, well, more so than in web development. So when I
create a variable, it gets allocated a
bit of memory somewhere (RAM I
assume). Instead of passing the
variable around, I pass a pointer to
that bit of memory around. And
pointers are declared by prefixing the
variable name with *.
Assuming I'm right, what puzzles me is why don't I need to do that for NSInteger?

NSInteger is a primitive type, which means it can be stored locally on the stack. You don't need to use a pointer to access it, but you can if you want to. The line:
NSInteger *processID = [[NSProcessInfo processInfo] processIdentifier];
returns an actual variable, not its address. To fix this, you need to remove the *:
NSInteger processID = [[NSProcessInfo processInfo] processIdentifier];
You can have a pointer to an NSInteger if you really want one:
NSInteger *pointerToProcessID = &processID;
The ampersand is the address of operator. It sets the pointer to the NSInteger equal to the address of the variable in memory, rather than to the integer in the variable.

The reason that you don't declare NSInteger with a * is because it isn't an object. An NSInteger is simply an int or a long:
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
endif
If it's being used in a 32-bit application, it's a 32-bit integer, and if it's being built in a 64-bit application, it's a 64-bit integer.
Of course, you can pass an NSInteger as a pointer, but most functions simply take arguments as an NSInteger and not a pointer to it.
Objects, on the other hand, can only be passed to other functions as pointers. This is because objects have memory dynamically allocated for them, and so cannot be declared on the stack. Since an int or long has a fixed amount of memory allocated for them, this is not an issue.

The * means “pointer”. The object variable holds a pointer to an object, so it has a *; the NSInteger variable holds an NSInteger, not a pointer to an NSInteger, so it does not have a *. Putting the * on that variable gives you at least a warning because you're putting an integer into a pointer variable.

NSInteger is just a typedef for int, AFAIK.

Working with pointers
NSInteger integer1 = 1;
NSLog(#"1. integer1:%ld &integer1:%p", integer1, &integer1);
//1. integer1:1 &integer1:0x7ffee59e8a98
NSInteger *integer2 = &integer1;
NSLog(#"2. integer2:%p &integer2:%p *integer2:%ld", integer2, &integer2, *integer2);
//2. integer2:0x7ffee59e8a98 &integer2:0x7ffee59e8a90 *integer2:1
*integer2 = 2;
NSLog(#"3. integer2:%p &integer2:%p *integer2:%ld \t integer1:%ld &integer1:%p", integer2, &integer2, *integer2, integer1, &integer1);
//3. integer2:0x7ffee59e8a98 &integer2:0x7ffee59e8a90 *integer2:2 integer1:2 &integer1:0x7ffee59e8a98

Related

int or NSInteger to NSUInteger for index

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.

NSInteger integer initialisation

Is there is no needs of declaring NSInteger using the alloc and initialise keyword? and why?
I was trying doing NSInteger *choice = [[NSInteger alloc] init]; while I found direct assignment
NSInteger is just typedef of int or long (depends on platform)
So you can initialize something like that
NSInteger i = 10;
Quote from SDK documentation
NSInteger
Used to describe an integer.
typedef long NSInteger;
When building 32-bit applications, NSInteger is a 32-bit integer. A 64-bit application treats NSInteger as a 64-bit integer.
https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html
NSInteger is not an Objective-C object. It's a datatype (much like C's int or char types). You do not need to call "alloc" (to explicitly allocate memory space) for it.
You can read up on the other Objective-C data types (like NSRange, which you'll use a lot of once you get into NSString objects) in this Apple documentation.

Having difficulties understanding pointers in Objective-C

So I understand that in ObjC everything lives in the Heap, and everything has a pointer to it. I'm reading through O'Reilys book and I'm grasping most things, but when I'm following through the tutorials/examples and something like this comes up
NSMutableArray *bar = [[[foo alloc] init] callMethod];
The * is right next to bar, but then you have things like
- (NSString *)createDeck:(NSString *)numOfCards;
Why is NSString * and not - (NSString)*createDeck:(NSString)*numOfCards;?
Any help understand things concept would be great thanks.
Edit:
NSUInteger *randomIndex = arc4random() % [deck count];
As Where
NSUInteger randomIndex = arc4random() % [deck count];
Works fine, how come removing the pointer in this case works?
tl;dr
The type is NSString * and that's why you have
- (NSString *)createDeck:(NSString *)numOfCards;
The return type and the argument type are enclosed within the parentheses.
Concerning the last question, an NSUInteger is not a object, despite the naming may suggest otherwise. Being a native type it lives on the stack and you don't need a pointer to it.
If you cmd-click on the type name, you'll find that it's actually a typedef for unsigned int (or unsigned long, depending on the architecture).
Discussion
Variables in C (and consequently in Objective-C) are declared using declarators, which are composed by a type and an identifier. In your example NSString * is the type and bar is the identifier.
NSString * bar;
^^^^^^^^^^ ^^^
type identifier
Declarators without an identifier are called abstract declarators, and are commonly used in C in three cases:
casting
float x = (float)2/4;
argument of sizeof()
sizeof(int *);
declaring argument types of a function
void foo(int *, float);
In Objective-C they are also used for return and argument types of methods, and that's why you have
- (NSString *)createDeck:(NSString *)numOfCards;
(Most of the information about declarators are adapted from http://nilsou.com/blog/2013/08/21/objective-c-blocks-syntax/)
Concerning the position of the asterkisk,
NSString *bar;
NSString * bar;
NSString* bar;
are all valid ways in to declare a variable of type pointer to NSString, aka NSString *.
Which one to use is a pure matter of personal taste, even though I believe the first one is the most common.

pointer to int conversion compiler trouble?

So I'm using Xcode to write a few tiny Objective-C apps and I have the line of code:
int * foo;
foo = 5;
NSLog(#"does it work... %i", foo);
Now it compiles and runs just fine, but I was wondering, why does it give me the warning, "Incompatible integer to pointer assigning..."? I thought the code above tells it to set whatever foo is pointing to to 5, not to set the pointer itself to 5. Can anyone help me out with this?
This piece of code works by accident: the int pointer happens to have sufficient space to hold an integer value, and NSLog reinterprets the pointer as an integer, but the program is still incorrect.
A pointer to int should be assigned an address of an integer variable, like this:
int *foo;
int var;
foo = &var;
Now you can assign the variable through the pointer:
*foo = 5;
You can also read the value through the pointer or through the variable:
NSLog(#"%d %d", *foo, var);

passing argument ... makes integer from pointer without a cast

How can I solve this problem?
code:
[NSNumber numberWithInteger:[buttonStatsInSection objectAtIndex:row]]
warning: passing argument 1 of 'numberWithInteger:' makes integer from pointer without a cast
Thanks.
numberWithInteger: needs you to give it an int to create the NSNumber. You are giving it an object, because objectAtIndex: returns an object.
Even if the object you have at that row is an NSNumber, or anything else, you still need to get an actual int data type out of it somehow.
For example, if the object you get back is an NSNumber, you could have something like this in the end:
NSNumber * myNSNum = [buttonStatsInSection objectAtIndex:row];
int myInt = [myNSNum intValue];
[NSNumber numberWithInteger:myInt];
Why are you creating a new NSNumber object? Do you really want a copy of it, or do you just want a reference to it? What do you plan to do with it? If you want a copy, you can just do:
NSNumber* copy = (NSNumber*)[[buttonStatsInSection objextAtIndex:row] copy];
Otherwise just do:
NSNumber* num = (NSNumber*)[buttonStatsInSection objextAtIndex:row];
Either way it isn't necessary to go through the process of extracting the int value and the converting it right back to an NSNumber