NSInteger integer initialisation - objective-c

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.

Related

NSUInteger should not be used in format strings?

Here's my code in all it's glory:
[NSString stringWithFormat:#"Total Properties: %d", (int)[inArray count]];
Which gets me an Xcode 5.1 warning:
Values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead
Ok so I'm confused. The value really is a 32-bit int, and I cast it to a 32-bit int. So what is this NSUInteger it's complaining about (the count I assume) and why doesn't this cast fix it?
NSUInteger and NSInteger are different lengths on 32-bit (int) and 64-bit (long). In order for one format specifier to work for both architectures, you must use a long specifier and cast the value to long:
Type Format Specifier Cast
---- ---------------- ----
NSInteger %ld long
NSUInteger %lu unsigned long
So, for example, your code becomes:
[NSString stringWithFormat:#"Total Properties: %lu", (unsigned long)[inArray count]];
There is very little work to do, really, because Xcode's Fix-It feature will do this for you automatically.
It is also possible to use the "z" and "t" modifiers for CPU-independent format strings, e.g.
NSInteger x = -1;
NSUInteger y = 99;
NSString *foo = [NSString stringWithFormat:#"NSInteger: %zd, NSUInteger: %tu", x, y];
The underlying type of NSUInteger changes based on the platform: it is a 32-bit unsigned integer on 32-bit platforms, and a 64-bit unsigned integer on 64-bit platforms.
In the Platform Dependencies section on of the String Programming Guide Apple suggests that you do the following:
To avoid the need to use different printf-style type specifiers depending on the platform, you can use the specifiers shown in Table 3. Note that in some cases you may have to cast the value.
For NSUInteger use format %lu or %lx, and cast the value to unsigned long.
Hence your code needs to be changed as follows to avoid the warning:
[NSString stringWithFormat:#"Total Properties: %lu", (unsigned long)[inArray count]];
You could also try using NSNumber methods:
[NSString stringWithFormat:#"Total Properties: %#", [[NSNumber numberWithUnsignedInteger:[inArray count]] stringValue]];

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.

What does the "at sign" # mean in this objective C code

I have been using Objective C for quite a few years but I didn't know # sign can be used like this (line 6 inside the for loop):
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeInteger:mti forKey:#"mti"];
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:N];
for (int i = 0; i < N; i++)
[arr addObject:#(mt[i])];
[coder encodeObject:arr forKey:#"mt"];
}
What does it mean? surprisingly I can remove it and the compiler does not complain and the code looks like working fine?!
This is part of MTRandom https://github.com/preble/MTRandom/blob/master/MTRandom/MTRandom.m#L115
In this context, the # operator converts a C numeric value (int, long, float, double, etc) into an instance of NSNumber. It's most often used with numeric literals (eg #3.5), but also applies to expressions as in your example.
This enhancement to the Objective-C language was introduced with Xcode 4.4.
It's a new syntax for boxing values with less typing. Assuming mt[i] is a numeric type, #(mt[i]) places it in an NSNumber object.
This is new to objective-C it turns the primitive integer into an NSNumber, there are also equivalents for NSArrays #(..) and NSDictionary #{...}

NSString (or NSArray or something) to variable parameter list of C (char *) strings

Is there any easy way to convert an Objective-C holding class of NSStrings into parameters for a function accepting a variable list of char *? Specifically I have a function like:
-(void)someFunction:(NSSomething *) var
that I want to forward to a C function like
void someCFunction(char * var, ...)
Is there an easy way to go about this?
No, you can only do what you want if the number of arguments you're passing is known at compile time. If you just want to convert a single string, use the -UTF8String message:
// Example with two strings
NSString *str1 = ...;
NSString *str2 = ...;
someCFunction([str1 UTF8String], [str2 UTF8String]); // etc.
But if the number of strings will vary at runtime, you'll need to use a different API, if one is available. For example, if there's an API that took an array of strings, you could convert the Objective-C array into a C array:
// This function takes a variable number of strings. Note: in C/Objective-C
// (but not in C++/Objective-C++), it's not legal to convert 'char **' to
// 'char *const *', so you may sometimes need a cast to call this function
void someCFunction(const char *const *stringArray, int numStrings)
{
...
}
...
// Convert Objective-C array to C array
NSArray *objCArray = ...;
int numStrings = [objCArray count];
char **cStrArray = malloc(numStrings * sizeof(char*));
for (int i = 0; i < count; i++)
cStrArray[i] = [[objCArray objectAtIndex:i] UTF8String];
// Call the function; see comment above for note on cast
someCFunction((const char *const *)cStrArray, numStrings);
// Don't leak memory
free(cStrArray);
This would do the trick:
NSString *string = #"testing string"
const char * p1=[string UTF8String];
char * p2;
p2 = const_cast<char *>(p1);
Yes, this can be done, and is explained here:
How to create a NSString from a format string like #"xxx=%#, yyy=%#" and a NSArray of objects?
And here:
http://www.cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html
With modifications for ARC here:
How to create a NSString from a format string like #"xxx=%#, yyy=%#" and a NSArray of objects?
Also, variable arguments are not statically or strongly typed, as the other poster seems to be suggesting. In fact, there is no clear indication in the callee of how many arguments you really have. Determining the number of arguments generally breaks down into having to either specify the number by an count parameter, using a null terminator, or inferring it from a format string a la (s)print* . This is frankly why the C (s)print* family of functions has been the source of many errors, now made much much safer by the XCode / Clang / GCC compiler that now warns.
As an aside, you can approach statically typed variable arguments in C++ by creating a template method that accepts an array of an unspecified size. This is generally considered bad form though as the compiler generates separate instances for each size of array seen by by the compiler (template bloat).

Why don't I declare NSInteger with a *

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