In Objective-C, I need to initialize an array of nulls/nil ( not sure which one to use ).
I have this code:
NSMutableArray * ObjectIndex = [[NSMutableArray alloc] initWithCapacity:maxObjectId];
for ( int i = 0; i < maxObjectId; i++ )
{
[ObjectIndex setObject:nil atIndexedSubscript:i];
}
I'm getting an error stating that object cannot be nil.
I plan on using this array to store objects in at certain indexes, leaving others nil(null?)
Later in the code:
for (Object * obj in objs)
{
ObjectIndex[obj.ID] = obj;
}
That is what NSNull is for. From the documentation:
The NSNull class defines a singleton object used to represent null
values in collection objects (which don’t allow nil values).
So you can fill your array with [NSNull null] instead of nil:
for (int i = 0; i < maxObjectId; i++ )
{
ObjectIndex[i] = [NSNull null];
}
Because [NSNull null] is a singleton object, you can check an array entry with
if ([ObjectIndex[i] isEqual:[NSNull null]]) {
// "empty"
}
Note: Names of Objective-C instance variables start usually with a lower case letter, so objectIndex would be a better name.
Rather than use a sparse array, why not us an NSMutableDictionary with the numbers as keys? That way you don't have to worry about prepopulating With nulls.
Alternatively, if you really want to use an array, I'd suggest initializing with either addObject: or insertObject:atIndex:
Simple! You can do it this way
NSMutableArray * ObjectIndex = [[NSMutableArray alloc] initWithCapacity: maxObjectId];
for(int i=0 ; i< maxObjectId ; i++) {
[ObjectIndex addObject:[NSNull null]];
}
Related
I need to have an NSMutableArray with a constant count of 9 where I can make index-specific insertions and deletions. I know that array = [[NSMutableArray alloc] initWithCapacity:9]; will declare an array with a capacity of 9, but when you get the size of the array, it returns 0.
My first attempt at a solution was to declare an array with capacity 9 (see above) and then fill it with NSNull objects. This code crashes with the error
[NSMutableArray insertObjects:atIndexes:]: array argument is not an NSArray'
- (void) setBlankArray: (NSMutableArray*)array {
for (int i = 0; i < 9; i++) {
[array insertObjects:[NSNull null] atIndexes:i];
}
}
-(void) addCurrentTile: (TileView*)aTile {
[currentTurnTilesArray insertObject:aTile atIndex: aTile.getValue-1];
}
-(void) removeCurrentTile: (TileView*)aTile {
[currentTurnTilesArray removeObjectAtIndex: aTile.getValue-1];
}
Is there a better way to accomplish it?
Not sure what you are trying to accomplish or why, but your removeCurrentTile will break it, because it will reduce the size of the array by 1. What you need to do is wrap this array with a class that guards it such that it can never never never have any other number of elements than 9.
Personally, I think what you're trying to do is silly. If you know you will always have exactly 9 slots, then you should start with a normal array, not a mutable array. It is the objects at each index that you want to mutate - not the array itself. For example, if these things were to be strings, then you would make an immutable array of 9 NSMutableString objects:
NSArray* arr = #[
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string]
];
Now each string can be mutated into another value, but no strings can be added or removed such as to change the length of the array.
Of course that's just an example (using strings, I mean). For maximum flexibility, this would be an NSArray of nine NSMutableDictionary objects. Now every NSMutableDictionary can contain anything, or nothing. But the number of NSMutableDictionaries will always be exactly nine, because the array itself is immutable.
You're looking for insertObject:atIndex:, or more simply addObject:.
[[NSMutableArray alloc] initWithCapacity:9] does not create an array with 9 elements.
It creates an empty array initialized with enough memory to hold 9 objects.
The purpose of this method is to allocate that much memory at once as you declare, so you can add elements to this array and system has not to allocate memory every time. This is only for optimization.
NSMutableArray reference
I just read your question, and I think I understand exactly what you need. Here is the code:
Declare a property:
#property (nonatomic, retain) NSMutableArray *myArray;
Synthesize it:
#synthesize myArray = _myArray;
Overrride its getter like this:
- (NSMutableArray *)myArray
{
if (!_myArray)
{
_myArray = [[NSMutableArray alloc] initWithCapacity:9];
for (int i = 0; i < 9; i++)
{
[self.myArray addObject:[NSNull null]];
}
}
return _myArray;
}
The "setBlankArray" method will simly set the property to nil, and next time you call the getter of the array property it will get automatically initialized with exactly what you need:
- (void)setBlankArray:(NSMutableArray *)array
{
self.myArray = nil;
}
VERY IMPORTANT: Do not write this code:
for (int i = 0; i < 9; i++)
{
[self.myArray addObject:[NSNull null]];
}
in the method just mentioned as this will make the array to contain 18 elements.
Then write the other 2 methods:
// you can also change the parameter from "id" to "TileView *"
- (void)addCurrentTile:(id)sender
{
NSInteger tileIndex = 1; // replace 1 with ((TileView *) sender).getValue - 1
[self.myArray replaceObjectAtIndex:tileIndex
withObject:sender];
}
// you can also change the parameter from "id" to "TileView *"
- (void)removeCurrentTile:(id)sender
{
NSInteger tileIndex = 1; // replace 1 with ((TileView *) sender).getValue - 1
[self.myArray replaceObjectAtIndex:tileIndex
withObject:[NSNull null]];
}
But, DO NOT FORGET to replace "id" with "TileView *", and TO SET the value of tileIndex to "((TileView *) sender).getValue - 1".
Hope this all makes sense, and is helpful for you.
Best regards
I have an NSMutableArray of NSNumbers, I want to enumerate through all of them with Objective-C styled enumeration. Here's what I've done so far.
for ( NSNumber* number in array )
{
//some code
}
I want to be able to recognize the first object fast, I am able to do this of course,
if ( [array indexOfObject:number] == 0 )
{
//if it's the first object
}
Is there any way to do this faster? There's of course the old-fashioned C style way, and remove the object from array first, and then put it back after enumeration. Just want to know if there's a better technic.
You can try using a method that provides the index of the object currently being enumerated:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx == 0) {
// this is the first object
}
}];
Or if you simply want to access the first object of an array:
id obj = [array objectAtIndex:0];
or with the new Objective-C style/syntax:
id obj = array[0];
This solution is faster than accessing and comparing the first array element:
BOOL firstIteration = YES;
for (NSNumber *number in array) {
if (firstIteration) {
// Handle first iteration
firstIteration = NO;
}
// Do something
}
In fast enumeration you cant alter the array. So if you want to remove you have to use old style for(;;) loop.
To find the first object simply use [array objectAtIndex:0]
Not sure if I am wording this correctly but what I need to do is iterate through an array sequentially but by 2 or 3 or 4 indices.
So you can iterate through an array like this
for(id arrayObject in NSArray) {
//do something amazing with arrayObject
}
which will iterate sequentially through each indexed object, [NSArray objectAtIndex: 0], [NSArray objectAtIndex: 1], etc.
so what if I just want object 0, 4, 8, 12, etc.
Thanks
Not quite. The way you wrote it, you are omitting the class of the arrayObject, and you are iterating through the NSArray class name rather than an instance. Thus:
for (id arrayObject in myArray) {
// do stuff with arrayObject
}
where myArray is of type NSArray or NSMutableArray.
For instance, an array of NSStrings
for (NSString *arrayObject in myArray) { /* ... */ }
If you want to skip parts of the array, you will have to use a counter.
for (int i=0; i< [myArray count]; i+=4) {
id arrayObject = [myArray objectAtIndex:i];
// do something with arrayObject
}
You could use enumerateObjectsUsingBlock: and check the index inside the block:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if( 0 == idx % 3 ){
// Do work
}
else{
// Continue enumeration
return;
}
}];
This would also allow you to operate on non-stride-based selections of your array, if necessary for some reason, e.g., if( (0 == idx % 3) || (0 == idx % 5) ), which would be much more difficult with a plain for loop.
I'd like to add, that there are also block-based enumeration methods, you could use.
NSMutableArray *evenArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx % 4 == 0)
[evenArray addObject:obj];
}];
Now evenArray will contain the objects with the indexes 0,4,8,… in the original array.
But often one will want to have just the filtered objects in the original array, and won't need a additionally mutable array.
I wrote some block-based convenient methods to achieve this:
array = [array arrayByPerformingBlock:^id(id element) {
return element;
} ifElementPassesTest:^BOOL(id element) {
return [array indexOfObject:element]%4 == 0;
}];
This will have the same result but hides the boilerplate code of creating and filling a mutable array.
You'll find my arraytools on GitHub.
You can do this with an NSEnumerator:
NSEnumerator *arrayEnum = [myArray objectEnumerator]; //Or reverseObjectEnumerator
for (MyThingy *thingy in arrayEnum) {
doThingyWithThingy(thingy);
[arrayEnum nextObject]; //Skip element
}
You can have zero or more nextObject messages at either point. For every third object, you would have two nextObjects at the end of the loop:
for (MyThingy *thingy in arrayEnum) {
doThingyWithThingy(thingy);
//Skip two elements
[arrayEnum nextObject];
[arrayEnum nextObject];
}
Basically, this is the same way you gather multiple objects in a single pass through the loop, only without actually using the other objects.
You can also have zero or more nextObject messages before the loop to skip some number of objects before the first one you want.
(I hope you're doing this to an array you read in, not one you generated yourself. The latter case is a sign that you should consider moving from array manipulation to model objects.)
Returning an array (Warning: Function returns address of local variable) ?
interface
int* decimalConversion(int iX);
implementation
int* decimalConversion(int iX){
int iMult[10] = {0,0,0,0,0,0,0};
...
return iMult; // <-- Warning: Function returns address of local variable
}
You should allocate space for the array, you're returning the address of an array that was created on the stack (hence local variable warning) if you're using C in that function use malloc(my_arr_size) if not use obj-c's alloc.
Example:
int *my_arr = calloc(10, sizeof(int)); //make sure we get zeroed memory
//fill array
return my_arr; //should no longer give a warning
When done with it just use free(my_arr) same as release. Reason I did this in C is because I can see that you're returning an int* type and using C style declarations so if you're doing it in Obj-c let me know and I can change my answer's example.
The reason you are getting this error is because local arrays get put on the stack, when you return that array you return an address in a stack frame. The problem is that when that method finishes execution that stack frame is no longer valid and therefore you cannot expect any data that was on that frame to be valid (although there are cases when this does work but it is considered bad practice). By allocating that array on the heap you can return a heap address where your data is assured to exist until you call free() on the pointer to that data.
If you are doing this for an app written in Objective-C, I would suggest using NSArray. NSArray is an Objective-C class for immutable arrays, and doesn't require that you manually allocate memory. The only turnoff is that you have to encapsulate your integers in NSNumber objects. An example would be:
NSArray * getNums (int num) {
NSArray * result = [NSArray arrayWithObjects:[NSNumber numberWithInt:num-1], [NSNumber numberWithInt:num], [NSNumber numberWithInt:num+1], nil];
return result;
}
...
NSArray * myList = getNums(10);
NSLog(#"First: %d", [[myList objectAtIndex:0] intValue]);
NSLog(#"Second: %d", [[myList objectAtIndex:1] intValue]);
NSLog(#"Third: %d", [[myList objectAtIndex:2] intValue]);
You can alternatively do this:
NSArray * getNums (int num) {
NSMutableArray * array = [NSMutableArray array];
[array addObject:[NSNumber numberWithInt:num-1]];
[array addObject:[NSNumber numberWithInt:num]];
[array addObject:[NSNumber numberWithInt:num+1]];
return array;
}
...
NSArray * myList = getNums(10);
for (int i = 0; i < [myList count]; i++) {
NSLog(#"myList[%d] = %d", i, [myList objectAtIndex:i]);
}
The only difference is that NSMutableArray allows you to add/remove elements after the fact.
I have an empty mutable array. Is it possible to insert object at index 2 for example, while there's nothing at index 0 and 1? I mean to increase capacity dynamically or something like that. .Regards.
NSMutableArray is not a sparse array; it does not allow empty slots that can be filled in later. initWithCapacity: just hints to the array that it will be filled to a certain amount; it isn't generally necessary in practice and, unless you know exactly how many items you are going to shove in the array, don't bother calling it (just use init).
A mutable array will quite efficiently grow in size as objects are added.
If you need a data structure that supports "holes", then either use something else or put a placeholder object in the slots that are supposed to be empty.
I.e. if you wanted an array with 10 slots, you might do:
NSMutableArray *a = [NSMutableArray array];
for(int i = 0; i<10; i++) [a addObject: [NSNull null]];
You can then check if the retrieved object isEqual: [NSNull null] to know if the slot is empty or not. And you can use replaceObjectAtIndex:withObject: to stick an object at a specific index.
Or you could use a different data structure; a dictionary with the indices as the keys would work, for example.
You can use a NSPointerArray for that.
NSPointerArray is a mutable collection
modeled after NSArray but it can also
hold NULL values, which can be
inserted or extracted (and which
contribute to the object’s count).
Moreover, unlike traditional arrays,
you can set the count of the array
directly.
NSPointerArray is available in OS X v10.5 and later and iOS 6.0 and later. If you target a lower OS version you can, for example:
Use a NSMutableDictionary, wrap you indices into NSNumbers and use these as keys.
Use a NSMutableArray and fill the "holes" with NSNull objects.
Write yourself a SparseArray class using an underlying NSMutableDictionary. Something like this (minimal code, barely tested, but it should give you the idea).
#interface SparseArray : NSObject {
#private
NSMutableDictionary* _dict;
int count;
}
-(SparseArray*)initWithCapacity:(NSUInteger)anInt;
-(id)objectAtIndex:(int)anIndex;
-(void)insertObject:(id)anObject atIndex:(int)anIndex;
- (void)removeObjectAtIndex:(int)anIndex;
-(int)count;
#implementation SparseArray
-(SparseArray*)initWithCapacity:(NSUInteger)anInt {
if ((self = [super init])) {
_dict = [[NSMutableDictionary dictionaryWithCapacity:anInt] retain];
count = 0;
}
return self;
}
-(id)objectAtIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
id object = [_dict objectForKey:key];
return object;
}
-(void)insertObject:(id)anObject atIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
[_dict setObject:anObject forKey:key];
count++;
}
- (void)removeObjectAtIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
id object = [_dict objectForKey:key];
if (object) {
[_dict removeObjectForKey:key];
count--;
}
}
-(int)count {
return count;
}
-(void)dealloc {
[_dict release];
[super dealloc];
}
#end