- Default value of variables at the time of declaration - - iphone

I was wondering what were the default values of variables before I initialized them...
For example, if I do :
//myClass.h
BOOL myBOOL; // default value ?
NSArray *myArray; // default value ?
NSUInteger myInteger; // default value ?
Some more examples here :
//myClass.m
// myArray is not initialized, only declared in .h file
if ([myArray count] == 0) { // TRUE or FALSE ?
// do whatever
}
More generally, what is returned when I do :
[myObjectOnlyDeclaredAndNotInitialized myCustomFunction];
Thank you for your answers.
Gotye.

The answer is that it depends on the scope in which the variable is defined.
Instance variables of Objective-C objects are always initialised to 0/nil/false because the memory allocated is zeroed.
Global variables are probably initialised to 0/nil/false to because when memory is first allocated to a process, it is also zeroed by the operating system. However, as a matter of course, I never rely on that and always initialise them myself.
Local variables are uninitialised and will contain random data depending on how the stack has grown/shrunk.
NB for pointers to Objective-C objects, you can safely send messages to nil. So, for instance:
NSArray* foo = nil;
NSLog(#"%# count = %d", foo, [foo count]);
is perfectly legal and will run without crashing with output something like:
2010-04-14 11:54:15.226 foo[17980:a0f] (null) count = 0

by default NSArray value will be nil , if you would not initialize it.

//myClass.h
BOOL myBOOL; // default value ?
NSArray *myArray; // default value ?
NSUInteger myInteger; // default value ?
the Bool myBool if not initialized will receive the default value of False.
NSArray *myArray if not allocated,initialized(for example NSArray *myArray = [[NSArray alloc] init];) will have the default value of NIL. if you call count on an unitialized array you will receive an exception not 0.
//myClass.m
// myArray is not initialized, only declared in .h file
if ([myArray count] == 0) { => here it should crash because of [myArray count]
// do whatever
}
for the NSUInteger myInteger the default value should be 0, the documentation says that this is used to describe an unsigned integer(i didn;t represent integers with this one though)
when you call [myObjectOnlyDeclaredAndNotInitialized myCustomFunction]; it should break, throw an exception.
hope it helps

Related

Only iOS 7 crash [NSNull intValue]: unrecognized selector sent to instance

I want to get data from JSON service. Only iOS 7 version crash when get data from JSON value.
It returns from JSON service below that:
{
voteAverageRating = 0;
voteCount = 0;
}
My code
int voteCount = [listDic objectForKey:#"voteCount"] intValue] ;
_LB_voteNumber.text = [NSString stringWithFormat:#"(%i)",voteCount];
Its work for iOS 5,5.1,6.0,6.1 but it crash only iOS7 version. It gave this error:
0x00098117 _mh_execute_header [NSNull intValue]: unrecognized selector
sent to instance
Then i changed my code below that;
NSString *voteCount = [listDic objectForKey:#"voteCount"] ;
_LB_voteNumber.text = [NSString stringWithFormat:#"(%#)",voteCount];
When runs this code. It crashed again only iOS 7 version. It gave this error:
0x00098117 _mh_execute_header [NSNull length]: unrecognized selector
sent to instance
How can i solve this problem ?
Put a check before accessing the value from JSON like,
if([NSNull null] != [listDic objectForKey:#"voteCount"]) {
NSString *voteCount = [listDic objectForKey:#"voteCount"];
/// ....
}
Reason for checking is, collection objects like NSDictionary do not allow values to be nil, hence they are stored as null. Passing intValue to a NSNull will not work as it will not recognise this selector.
Hope that helps!
As the others have said, JSON null will be deserialized to NSNull. Unlike nil, You cannot send (most) messages to NSNull.
One solution is to add an implementation of -intValue on NSNull via category:
#implementation NSNull (IntValue)
-(int)intValue { return 0 ; }
#end
Now your code will work since sending -intValue to NSNull will now return 0
Another option: You could also add an "IfNullThenNil" category to NSObject...
#implementation NSObject (IfNullThenNil)
-(id)ifNullThenNil { return self ; }
#end
#implementation NSNull (IfNullThenNil)
-(id)ifNullThenNil { return nil ; }
#end
Now, your code becomes:
int voteCount = [[[listDic objectForKey:#"voteCount"] ifNullThenNil] intValue] ;
Just add a call to -ifNullThenNil wherever you access values from a JSON object.
For me this is worked
NSArray* merStore = [tmpDictn objectForKey:#"merchantStore"];
if ([merStore isKindOfClass:[NSArray class]] && merStore.count !=0)
{
for(int n = 0; n < merStore.count; n++)
{
NSMutableDictionary *storeDic = [merStore objectAtIndex:n];
[latitudeArray addObject:[storeDic objectForKey:#"latitude"]];
}
}
I hope it helps some one. If you need any help let me know.
That's quite normal. JSON can send null values to your app. If it does, then this is done intentionally by the server and it expects you to handle it. Figure out what the correct behaviour is when a null value is received. Then when you get an object that could be a null value, check
if (object == [NSNull null])
{
// stuff to handle null objects
}
else
{
// stuff to handle non-null objects
}
The real problem isn't that your app crashes, but that your app doesn't handle JSON data that it is supposed to handle.

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

how to detect if an array isnt empty?

I am trying to detect if an array isn't empty in order to be able to do a certain call.
I tried using if (![array ==nil]) however that doesn't compile.
I'm sure there is a really easy explanation to this.
Update
If array is empty I want to do this:
array = [[NSMutableArray alloc]init];
If it has an object I want to do this:
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
If you declared it but did not assign anything to it at all:
NSMutableArray *array;
Then the array will be nil, meaning it isn't there at all so you can't say if it's empty or not, so you can't check anything.
If you did assign something to it, and you want to find out if the existing array is empty or not, that would depend on how you created it first.
If the array was assigned from some convenience method, it's autoreleased, so just do this:
if ([array count] == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
If the array was assigned from an init or copy method, or it was retained previously, store the count in a temporary variable, release the array and use the temporary variable to decide what to do:
NSInteger count = [array count];
[array release];
if (count == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
In your case I'd always use without differentation
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
and set the default value in the user defaults to an empty array right away at program start before accessing the defaults (from Apple's example):
+ (void)initialize{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:[NSArray array] forKey:#"MyFavorites"];
[defaults registerDefaults:appDefaults];
}
See Apple's doc on this.
Supposing you are talking about NSArray, if myArray has not been properly alloced+initialized (what you are trying to check) its reference will be nil, so you can do:
if(myArray) //or even if(myArray != nil) since myArray will be a pointer
{
//properly inizialized
}
else
{
//not properly inited
}
If it's been inited on the other hand, you can test its emptiness by checking the count property which returns the number of elements it contains
if([myArray > 0])
//there is at least one element
}
else
{
//no elements
}
you can use count function of NSArray. it will work on NSMutableArray too....
syntext will be,
int ct=[array count];
ct will have number of items in array.
if it us empty it will be Zero

String identifies iVar to update

I have a series of 5 iVars. (highscore01, highscore02, highScore03, highScore04, highScore05) I want to update a particular iVar with an integer value. The iVars are defined as ints. The iVars are in a Class called HighScores.
The particular iVar to be updated is the one with the lowest current value stored in it. I want to replace the lowest value with a new value.
I have a method that identifies the ivar with the lowest value and returns a String "theString" containing the name of the iVar to be updated.
My question: How do I use the "theString" to update the correct iVar.
Here is a sample of the code.
// If any of the highScore iVars contain 0, then they are still empty.
// Find the first empty iVar and store score there.
if (scoreVarsFullFlag == NO) // Flag to indicate if any iVars are still zero
{
if (theHighScores.highScore01 == 0)
theHighScores.highScore01 = mainScores.scoreTotal;
else if (theHighScores.highScore02 == 0)
theHighScores.highScore02 = mainScores.scoreTotal;
else if (theHighScores.highScore03 == 0)
theHighScores.highScore03 = mainScores.scoreTotal;
else if (theHighScores.highScore04 == 0)
theHighScores.highScore04 = mainScores.scoreTotal;
else if (theHighScores.highScore05 == 0)
{
theHighScores.highScore05 = mainScores.scoreTotal;
scoreVarsFullFlag = YES; // Last scores iVar turns nonzero - set Flag to YES, to indicate no non-zero iVars
}
}
else
{
NSLog(#"The Lowest is at %#", [theHighScores findLowestHighScore]);
NSString * theString;
theString = [NSString stringWithString:[theHighScores findLowestHighScore]];
NSLog(#"The String is: %#", theString);
theHighScores.theString = mainScores.scoreTotal; // This fails
}
The last line is where I try to set the iVar identified in "theString" to the new score number. "theString" does contain the name of the iVar to update, i.e. "HighScore03", etc.
If I was setting this manually, it would be;
theHighScores.highScore03 = mainScores.scoreTotal;
Any insight would be much appreciated.
If I were you I'd just use a mutable array instead to allow sorting and easily pick off the lowest item.
///store this in your app delegate
NSMutableArray *highscores = [[NSMutableArray alloc] init];
//then when you want to add a high score
[highscores addObject:[NSNumber numberWithDouble:mainScores.scoreTotal]];
NSSortDescriptor *myDescriptor;
myDescriptor = [[NSSortDescriptor alloc] initWithKey:#"doubleValue" ascending:NO];
[highscores sortUsingDescriptors:[NSArray arrayWithObject:myDescriptor]];
///remove the last object if it's over 5
if ([highscores count]>5) {
[highscores removeLastObject];
}
I think mjdth's solution is probably the best, but you could also use -setValue:forKey:, though you'd have to switch to using NSNumbers, rather than ints.
[theHighScores setValue: [NSNumber numberWithInt: mainScores.scoreTotal] forKey: [theHighScores findLowestHighScore]];
Sounds like you're trying to do some basic type introspection. Specifically, using NSSelectorFromString.
int newValue = 1;
SEL methodName = NSSelectorFromString(#"setHighScore03:");
[theHighScores performSelector:methodName withObject:newValue];