Xcode Gives Strange Output From NSArray - iphone

When I run this code, the output is some 1084848 to the console. I can't figure out why such odd output... here is the code.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
int someNumber = 3;
[array addObject:[NSNumber numberWithInt:someNumber]];
NSLog(#"%i" , [array objectAtIndex:0]);
[pool drain];
return 0;
}

the "%i" format specifier expects an integer, not an Object.
Try NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
XCode is probably giving you a warning on this line: something like "Conversion specifies type 'int', but argument has type 'id'".

Here's the pseudocode of your program:
//
// Inside of your main function....
//
// Set up the Autorelease pool and then create an array
//
// Declare an int
//
// Add the int to an array, while wrapping it in an NSNumber
//
// Log the value of the first object in the array, using the int formatter
//
// Clean up and return
//
You are logging the first object in the array, but NSArray cannot hold a primitive that's not wrapped in an Objective-C object.
To better understand your code, try changing these lines of code:
int someNumber = 3;
[array addObject:[NSNumber numberWithInt:someNumber]];
Expand them a little. Try this:
int someNumber = 3;
NSNumber *aNumber = [NSNumber numberWithInt:someNumber];
[array addObject:aNumber];
So, you've correctly wrapped the int in an NSNumber, but you're not unwrapping it. You need to ask your NSNumber for the int that it holds like so:
[[array objectAtIndex:0] intValue];
Or, to do the logging in one line:
NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
The characters "%i" is called a "formatter". Different kinds of values require different formatters. When you are using an Objective-C object, you use "%#". For an NSInteger or int, you'd use %i. For a float, you'd use "%f". The point is that you need to either unwrap that number, or use the Objective-C formatter for strings.
A quick note about that weird value you were getting earlier: That's a memory address in RAM. It's the closest thing you're going to get when you use an incorrect formatter. In some cases, using the wrong formatter will cause an EXC_BAD_ACCESS. You were "lucky" and got a weird value instead of a dead program. I suggest learning about strings and formatters before you move on. It will make your life a lot easier.

When you use %i for integer values then you should give arguments as integer as below
NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
But when you want object to be displayed then you must use %# which identifies object in general case as below:
NSLog(#"%#", array);

Related

NSMutableArray Crashing App

In one class, I define an NSMutableArray with getters and setters:
#interface ArrayClass : NSObject {
NSMutableArray *array;
}
#property (nonatomic, strong) NSMutableArray *array;
#end
Then within the implementation file, I alloc init the mutable array:
#import "ImageUploader.h"
#implementation ArrayClass
#synthesize array;
- (id)init {
self = [super init];
if (self != nil) {
NSLog(#"ArrayClass inited");
array = [[NSMutableArray alloc] init];
}
return self;
}
#end
Then I initialize an instance of this class from another class:
ArrayClass *arrayClass = [[ArrayClass alloc] init];
[arrayClass.array addObject:image];
NSUInteger count = [arrayClass.array count];
NSLog(#"%#", count);
But when I try to add an object to the mutable array, the app crashes and Xcode 4.3 shows:
Removing the addObject call makes the app run fine. What am I doing wrong that would cause the app to crash?
This is wrong:
NSUInteger count = [arrayClass.array count];
NSLog(#"%#", count);
You want:
NSLog(#"%u", count);
%# is used to specify that the argument is an object. However, an NSUInteger is a primitive value, not an object. You use %u for unsigned ints.
try:
NSLog(#"%i", count);
NSUInteger return an INT not an object address
NSLog(#"%#", count);
is wrong, use:
NSLog(#"%i", count);
%# in the format statement expects and must be an object, NSUInteger is in int, not an object.
You are using an %# format specifier, which is for Cocoa objects only, for an NSUInteger, which is a typedef on an ordinary unsigned int. Use %d, %i or %u instead.
It looks to me like it's crashing when trying to print description, which makes sense because you're using %# where an integer is expected in your NSLog().
Separately, using a mutable property is almost always a bad idea. If it's really a property, you probably want to use an immutable array, and set the whole array when you want to change it.
Agree that the logging of count is wrong, but I think the other answers miss a move obvious point: the crash happens on the addObject. This implies that image is nil. NSLog that before the add.

Why is my Objective-C class instance variable not being set?

this is a noob question but I cannot for the life of me figure out why my MSMutableArray class variable is not being set. Below is my code:
#interface MyClass : NSObject {
NSMutableArray *imageArr;
}
#implementation MyClass
-(id)init
{
self = [super init];
if (self) {
imageArr = [[NSMutableArray alloc] init];
}
return self;
}
- (void) checkImageArr {
NSLog(#"imageArr size::%#",[imageArr count]);
}
When this code runs, the following is set to the log:
imageArr size::(null)
Why is that variable not being set? I looked at the following question and don't see anything different between my code and the accepted answer.
Thanks.
The %# specifier expects the argument to be an id (or pointer to an object). -count returns an NSUInteger which is not an object. Since your array is empty, the count is zero and so the argument is being interpreted as a nil object, which comes out as (null) when used with the %# specifier.
If the argument was not nil, -description would be sent to it to get a string to insert in the log message. So, if you add an object to your array, NSLog will try to interpret 1 as an object pointer and send -description to it. This will cause an EXC_BAD_ACCESS exception (try it!).
You need a format specifier that interprets the argument as a number. NSUinteger has the following definition
#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef unsigned long NSUInteger;
#else
typedef unsigned int NSUInteger;
#endif
so it's probably an unsigned long. For safety, I always cast it to make sure, so you need this:
NSLog(#"imageArr size::%lu", (unsigned long)[imageArr count]);
Change %# to %lu and you'll see.
The count method returns an NSUInteger.
Try this log format instead:
NSLog(#"imageArr size::%u",[imageArr count]);
NSLog(#"imageArr size::%#",[imageArr count]);
You should use %# when you want to "write an object" AFAIK, it is like write [object description].
[imageArr count] is a int, right? It is not a pointer to an object.
You should use %i instead of %#. And size will be 0.
Try NSLog(#"imageArr size::%#",imageArr); if you want to write a address

objective c: passing a char argument to function crashes the app

I wrote a singleton called SomeValues where I initialize a foo NSMutableArray. I then tried to write a function SetBFSV to set the values of this array from different control views.
#interface SomeValues : NSObject {
NSMutableArray *foo;}
+ (SomeValues *) sharedInstance;
#implementation
...
- (void) SetBFSV:(char)lbl ToVal:(long)BFSvl{
NSNumber *ValueBFSvl = [NSNumber numberWithLong:BFSvl];
NSString *Strlbl = [[NSString alloc] stringWithFormat:#"%s",lbl];
[foo setValue:ValueBFSvl forKey:Strlbl];
}
I know that setValue requires a NS object for both the value and the key, but I cannot declare my function as
(void) SetBFSV:(NSString)lbl ToVal:(NSNumber)BFSvl
because it doesn't compile with the error: "Can not use an object as parameter to a method".
In one ControlView I wrote then this piece of code:
SomeValues *myBFSV = [SomeValues sharedInstance];
const unsigned char *Bar = (unsigned char *)[#"Label1" UTF8String];
NSLog(#"The string %s", Bar);
[myBFSV SetBFSV:Bar ToVal:2.5];
When compiling I get a warning on the last line:
warning: passing argument 1 of 'SetBFSV:ToVal:' makes integer from pointer without a cast
Which integer? I'm getting stupid looking around for it. When running I get the print out from the NSLog, but right afterwards the program obviously crashes with this error:
'NSInvalidArgumentException', reason: '-[NSPlaceholderString stringWithFormat:]: unrecognized selector sent to instance 0x4e03280'
Clearly I'm passing something wrong to stringWithFormat but I cannot understand what.
Thanks for any help. Have a nice day!
/luca
Possible problems with your code (unless you have typos in it):
- (void) SetBFSV:(char)lbl ToVal:(long)BFSvl function expects char as its 1st parameter but you pass it a char* - your 1st warning probably comes from here
stringWithFormat is a class method so your code should look either:
NSString *Strlbl = [[NSString alloc] initWithFormat:#"%s",lbl];
[foo setValue:ValueBFSvl forKey:Strlbl]
or
NSString *Strlbl = [NSString stringWithFormat:#"%s",lbl];
[foo setValue:ValueBFSvl forKey:Strlbl]
since you try to use -stringWithFormat instead of +stringWithFormat you get a crash
If you pass char to a function then correct format specifier for it will be %c, not %s
You probably must release your Strlbl variable if you create it with alloc/init otherwise it will leak (but you must not release it if you use +stringWithFormat:)
For one, you can't use an object as a paramter:
(void) SetBFSV:(NSString)lbl ToVal:(NSNumber)BFSvl
You need to pass them as pointers, using the asterisk.
(void) SetBFSV:(NSString*)lbl ToVal:(NSNumber*)BFSvl
Furthermore, if you need to pass them as (char) and (long) your bit of code:
SomeValues *myBFSV = [SomeValues sharedInstance];
const unsigned char *Bar = (unsigned char *)[#"Label1" UTF8String];
NSLog(#"The string %s", Bar);
[myBFSV SetBFSV:Bar ToVal:2.5]; // in either case, this is a long. why are you passing a double here?
Passes *Bar as a pointer. You should really read up on the pointers and objects. IF you need to pass them in as (const char*) and (long) do it like this:
- (void) SetBFSV:(const char*)lbl ToVal:(long)BFSvl{
NSNumber *ValueBFSvl = [NSNumber numberWithLong:BFSvl];
NSString *Strlbl = [NSString stringWithUTF8String: lbl]; // your old code had a memory leak here. you need to either create an autorelease object, or release it after adding to `foo`
[foo setValue:ValueBFSvl forKey:Strlbl];
}
My Recommendation is to do the following:
- (void) SetBFSV:(NSString*)key ToVal:(long)val{
NSNumber *value = [NSNumber numberWithLong:val];
[foo setValue:value forKey:key];
}
And call it like the following (from your example):
SomeValues *myBFSV = [SomeValues sharedInstance];
NSString *Bar = [NSString stringWithString:#"Label1"];// this may not be necessary...
NSLog(#"The string %#", Bar);
[myBFSV SetBFSV:Bar ToVal:25]; // don't pass a decimal for a (long)

Convert NSString to Integer in objective - c

I have an array that stores each digit of a phone number as a string. I then pass the phone number digit string as an argument for objectAtIndex: method of NSArray like this: [myArray objectAtIndex: [myString intValue]]; The compiler says I need to cast the String but I am already doing that. What is wrong?
Update:
Here's my actual line of code:
NSMutableArray *tmp = [[NSMutableArray alloc] initWithArray:[charHolder objectAtIndex:[[phoneNumDigits objectAtIndex:i]intValue]]];
This is where the error is, phoneNumDigits is an array of each digit of the phone number, charHolder is the array holding the array of letters associated with each digit.
Your question is a little confusing to me. Here is how I understand what you want to do:
You have an NSArray named phoneNumDigits. This array contains a few NSString objects. Each string is something like #"1" or #"4" and represents a single digit of a phone number.
Now you want to convert each of those digit strings to int or NSInteger and want to store these integers in another array.
If I understood you correctly, here is my answer:
You cannot exactly do what you want, because you can't put a simple data type like an int or a float into an NSArray.
That's why there is the wrapper class NSNumber. You can package a simple int in an NSNumber and store this NSNumber in an NSArray.
So to get your string digits from the phoneNumDigits into the tmp array you could use this code:
for (NSString *digitAsString in phoneNumDigits)
{
NSNumber *digitAsNumber = [NSNumber numberWithInt:[digitAsString intValue]];
[tmp addObject:digitAsNumber];
}
To get the ints out of the tmp-NSArray you would use
int digit = [[tmp objectAtIndex:idx] intValue];
I hope this helps, but I'm not sure I understand what you want to do here. I could be completely missing the point. Maybe you could share some more code.
NSMutableArray *tmp = [[NSMutableArray alloc] initWithArray:[charHolder objectAtIndex:[[phoneNumDigits objectAtIndex:i]intValue]]];
objectAtIndex returns a generic object (id). It has no idea that the object in the array is a string as it could be anything. So you need to cast it. Or to increase readabilty, create variables for them. Eg:
int phoneNumberDigit = [phoneNumDigits objectAtIndex:i];
NSArray *chars = [charHolder objectAtIndex:phoneNumberDigit];
NSMutableArray *tmp = [[NSMutableArray alloc] initWithArray:chars];

Array Allocation in Objective C++

I want to declare an array of numbers that is flexible in size in an obj C file
I am doing this:
long * arr = NULL;
a[0] = 0;
but this is giving bad_excess error
Can anyone help me out
also
long *arr = malloc(sizeof(long));
doesn't seem to help either
Why don't you do something like this,
NSMutableArray *numArray = [[NSMutableArray alloc] init];
This creates a array of objects. You can add any number of objects to it. Here you want to add long values. So use the following code,
[numArray addObject:[NSNumber numberWithLong:37];
[numArray addObject:[NSNumber numberWithLong:45];
[numArray addObject:[NSNumber numberWithLong:12];
NSMutableArray is flexible in size as you expected. You can add any number of objects.
If you want to get the number, you can do like the following,
long num1 = [[numArray objectAtIndex:0] longValue];
long num2 = [[numArray objectAtIndex:1] longValue];
You can also do as specified in the following link,
How to declare an array of floats as a class variable in Objective-C when the dimension is undefined at the class instantiation time?