noobsmcgoobs
noobsmcgoobs

Reputation: 2746

Efficiently fill multiple NSMutableArray with same NSString

I have an NSMutableArray of capacity 7. I want to put in each index a NSMutableArray with capacity 6. In each of these 6 slots, I want the character A.

The other requirements are that I need to be able to access each index in each of the arrays. I previously had code like this

-(id)init{

    self = [super init];

    self.array = [[NSMutableArray alloc]initWithCapacity:7];

    for (NSUInteger i = 0; i < self.board.count; i++) {
        NSMutableArray *subArray = [[NSMutableArray alloc]init];
        for (NSUInteger i = 0; i <subBoard.count; i++) {
            [subArray addObject:@"A"];
        }
        [self.array insertObject:subArray atIndex:i];
    }

    return self;
}

The problem was that when I wanted to find an index in the subArray from access the main array, I'd have to do all sorts of casting and creating new variables to show that those pointers were NSMutableArrays.

Then I had this code

#import <Foundation/Foundation.h>

@interface NewArray : NSMutableArray

@property (strong, nonatomic) NSMutableArray *column1;
@property (strong, nonatomic) NSMutableArray *column2;
@property (strong, nonatomic) NSMutableArray *column3;
@property (strong, nonatomic) NSMutableArray *column4;
@property (strong, nonatomic) NSMutableArray *column5;
@property (strong, nonatomic) NSMutableArray *column6;
@property (strong, nonatomic) NSMutableArray *column7;
-(id)init
@end

But how do I write the init method, so I don't have to do something like this

-(id)init{

    self = [super init];

    self = [[NSMutableArray alloc]initWithCapacity:7];
    self.column1 = [[NSMutableArray alloc]initWithCapacity:6];
    [self insertObject:self.column1 atIndex:0];
     //etc. for each additional array to be added
    return self;
}

Also, I'd have to add the character to each array separately. Seems really inefficient. I'd like to know if there is a smarter way.

Upvotes: 3

Views: 223

Answers (3)

gnasher729
gnasher729

Reputation: 52538

First, never, ever even think about subclassing any of the basic classes like NSArray, NSMutableArray, NSString and so on. Apart from being an awfully bad idea in any language, it's especially bad in Objective-C because NSMutableArray for example is part of a class cluster and your chances of getting this to work properly are practically nil.

Second, there are times when you should use plain old C. Declare an object, derived from NSObject, and if you want a two-dimensional array of char, you give it a member char rowsColumns [7][6].

Upvotes: 1

hariszaman
hariszaman

Reputation: 8424

If you don't care about the capacity as explained here that it does make much of the difference. How about writing something like this

NSMutableArray *myArray = [@[
                             [@[@"A"] mutableCopy]
                             ] mutableCopy];

myArray[0][0] = @"B";

Upvotes: 0

rmaddy
rmaddy

Reputation: 318804

Your first approach is much better than the second. But I'd made a few changes to make it better.

Start with the property:

@property (strong, nonatomic) NSMutableArray<NSMutableArray<NSString *> *> *columns;

This declares that you have a mutable array that contains mutable arrays that contain strings.

Then your init method:

- (instancetype)init {
    self = [super init];
    if (self) {    
        _columns = [[NSMutableArray alloc] initWithCapacity:7];

        // Just create one subarray filled with "A"
        NSMutableArray<NSString *> *subArray = [[NSMutableArray alloc] initWithCapacity:6];
        for (NSUInteger i = 0; i < 6; i++) {
            [subArray addObject:@"A"];
        }

        // Now fill the main array with copies of the sub-array
        for (NSUInteger i = 0; i < 7; i++) {
            [_columns addObject:[subArray mutableCopy]];
        }
    }

    return self;
}

Note that you referencing the count property in the for loop won't work. It starts out empty so count will be zero and the loop won't execute.

Now you can access a specific value as simply as:

NSString *value = self.columns[4][3]; // read

self.columns[2][5] = @"Hello"; // write

Upvotes: 5

Related Questions