NSMutableArray Extra Nil Sentinels - ios

I've read a text file into an array of strings. In the below code I'm creating objects from that array and adding them into an NSMutableArray.
NSMutableArray* metaphors = [[NSMutableArray alloc] init];
unsigned int i, cnt = [allLinedStrings count];
for(i = 0; i < cnt-3; i+=5)
{
Metaphor *newMetaphor = [[Metaphor alloc] init];
[newMetaphor setMetaphorTitle: allLinedStrings[i]];
[newMetaphor setCorrectAnswer: allLinedStrings[i+1]];
[newMetaphor setLiteralAnswer: allLinedStrings[i+2]];
[newMetaphor setWayOffAnswer: allLinedStrings[i+3]];
[metaphors addObject:newMetaphor];
}
As for the problem, when I access any item via index ([metaphors objectAtIndex:3] for example) every other element (odd numbered ones) are nil elements. All of the objects are added to the array, though. My guess is that addObject is adding an element to the array as well as a new nil sentinel every time? Should this be happening/should I manually go through and remove these elements?
Also a side note, as I'm new to Objective-C, my Metaphor class contains the 4 instance fields you can see within the body: I'm sure there is quicker syntax to initialize one of these objects if anyone could point me the right way. Thanks.

NSArray can't contain nil. It's invalid. If you are getting nil back in a call to an array, the array pointer itself is almost certainly nil. (You CAN send messages to a nil object pointer in Objective C. It simply returns nil/zero.)
Trying to add a nil to an NSArray will cause a crash, and trying to index past the end of an NSArray will also crash.
There is a special class NSNull that provides a singleton placeholder object that can take the place of a nil entry in an NSArray.

The nil sentinel is only a way to know the last element of a variable length array has been reached. The nil sentinel ISN'T added to the NSMutableArray;
NSMutableArray addObject method doesn't need a nil sentinel as you only add ONE object, not a variable length array.
If you need to add something "nil" to an array, you might use [NSNull null] which is an object "equivalent to nil".

Related

Objective C - NSArray's indexOfObject: not work

I use [items indexOfObject:items.lastObject] to get the last index, but this code returns nil. Why does this happen?
The first and last object in your array are both bar button items created with the system item of "fixed space".
The result of calling indexOfObject: is 0, not nil. This means that the object is being found at index 0. indexOfObject: can't return nil. If an object isn't found, it returns the special value NSNotFound which is the unsigned value for -1.
From the documentation for indexOfObject::
Starting at index 0, each element of the array is passed as an argument to an isEqual: message sent to anObject until a match is found or the end of the array is reached. Objects are considered equal if isEqual: (declared in the NSObject protocol) returns YES.
The implementation of UIBarButtonItem isEqual: will return YES if two bar button item instances are created with the same system item (and probably a few other properties as well).
indexOfObject: is not based on the instance of the object, it's based on isEqual:.
If you want to find the index of an object based on the identity (its address) of the object instead of isEqual:, use indexOfObjectIdenticalTo:.
p [items indexOfObjectIdenticalTo:items.lastObject]
will give you 6 instead of 0.

how to fix initializing nsmutable array strong with an expression of incompatible type void warning?

I am using this code NSMutableArray * nst = [navigationArray removeObjectAtIndex:navigationArray.count-1]; to remove some object in a nsmutablearray but i am getting "nsmutable array strong with an expression of incompatible type void warning" can any one help how to fix it.
You should do something like this
NSMutableArray * nst = [NSMutableArray arrayWithArray:navigationArray ];
[nst removeObjectAtIndex:navigationArray.count-1];
NSLog(#"%#",nst);
This way, navigation array stays intact as it was, and nst is a new array with the navigation array content and the objects removed at the specific index.
OR
If you want to remove those contents straight away from navigationArray, then
[navigationArray removeObjectAtIndex:navigationArray.count-1]
This will make the objects removed from the navigationArray itself.
Xcode is complaining coz, [removeObjectAtIndex] doesn't returns an array and you are trying to assign nst to the return value of the method.
Hope could make u understand.

Passing Null Values and a variable in to NSMutableArray/NSArray. Why is there a difference in output?

My question is how to pass Null values in to NSMutableArray/NSArray.
But by searching google and going through different sites, i think that i have achieved my purpose. But, while trying i got a new doubt.
See the below code to understand my question
I am declaring a mutable array and initializing it with some objects initially and also i am passing a null in to it at the time of declaration itself.
Now when i run this code below
NSMutableArray * mar = [[NSMutableArray alloc]initWithObjects:#"first",#"last", nil];
[ar addObject:[NSNull null]];
NSLog(#"%#",mar);
The o/p is :
(
first,
last,
"<null>"
)
But my actual doubt is when i initialize the NSMutableArray as below
NSString *str;
NSMutableArray * mar = [[NSMutableArray alloc]initWithObjects:#"first",str,#"last", nil];
[ar addObject:[NSNull null]];
NSLog(#"%#",mar);
The o/p is :
(
first,
"<null>"
)
The 2nd element in the array is "null", i understand that as i have passed a variable without assigning any value to it. It is printing null. But why are the remaining elements not printed.
According to what i know, the array will stop adding elements whenever it overcomes nil while initializing. But here, in this case. The o/p shows that the 2nd element is also null.(But not nil.)
Then why does the remaining elements are not printed.
UPDATING QUESTION
NSString* str;
NSLog(#"%#",str);
NSMutableArray * mar = [[NSMutableArray alloc]initWithObjects:#"first",str,#"last", nil];
NSLog(#"%#",mar);
and the o/p for the above code is
(null) // for str an uninitialised NSString variable.
(
first // first element in the array
)
If the value present in str is (null), how come the array encountered nil and stopped adding elements to array and printing them.
Now, someone answer this?
initWithObjects uses nil as the marker for the last item. If you pass a nil (the unitialized str variable) to it as the 2nd item out of 4, only the first one is actually added.
[[NSMutableArray alloc]initWithObjects:#"first",str ?: [NSNull null],#"last", nil];
will fix your problem by replacing the nil with a [NSNull null].
Also see NSArray creation with variable argument lists
in objective-C, when iterating through Array if nil/null encountered then it gets treated as end of array.
this is the reason it is not printing remaining values.
in case you want clear diff between nil/null/Nil then check Difference between nil, NIL and, null in Objective-C

How to replace object index in NSMutableArray in iPhone

I have two different arrays and I want to check firstArray objects and accordingly insert objects in second array.If my firstArray contains particular object then at that index, I am trying insert value in secondArray.
Currently, I am inserting values like :
[secondArray replaceObjectAtIndex:0 withObject:transIdArray];
[secondArray replaceObjectAtIndex:1 withObject:fullCaseArray];
[secondArray replaceObjectAtIndex:2 withObject:caseTitleArray];
[secondArray replaceObjectAtIndex:3 withObject:filingDateArray];
My problem is, If in firstArray transIdArray is at 2 index then my these two arrays data getting mismatched.Please suggest me better way to check add insert values in arrays. Thanks.
NSArray elements are naturally packed together, not sparse, like C arrays can be. To accomplish what you want, the secondArray needs to carry placeholders that are considered non-objects semantically by your app. [NSNull null], an instance of NSNull (not to be confused with nil) is a common choice.
You could initialize one or both arrays like this:
for (NSInteger i=0, i<SOME_KNOW_MAX_LENGTH; ++i) {
[secondArray addObject:[NSNull null]];
}
Then an instance of NSNull in the second array means 'there's nothing at this index in this array corresponding to firstArray'. And you can check if that condition holds for a given index like this:
id secondArrayElement = secondArray[index];
if ([secondArrayElement isMemberOfClass:[NSNull class]]) { // ...
As an aside - often, when I find myself needing to coordinate parallel arrays, it usually means I have some undone representational work, and what I really need is a single array with a more thoughtful object, or the containing object must be more thoughtfully designed.

I have an if statement nested in a for-in loop that evaluates incorrectly

I'm using a for-in loop to get each object out of a dictionary of objects (passingObservations) and placing certain ones in an array of objects. It checks for a specific NSString #Property of the object and see if it is equal to another NSString. When equal, it places the object into schoolMArray. The if statement evaluates TRUE for the first run through the for-in loop and adds the object to the schoolMArray. On successive loops through the for-in, it evaluates FALSE. It shouldn't be doing that though. I've put in exact copies of the same object and it still evaluates the second object as FALSE.
for (NSString *key in keysArray) {
ObservationData *obj = [self.passingObservations objectForKey:key];
if (obj.districtName == self.passingDistrict) {
[schoolMArray addObject:obj];
}
}
What have I done wrong here?
You compared objects for equivalence using == rather than isEqual: (or, in the specific case of strings, isEqualToString:).

Resources