views:

476

answers:

2

Just a conceptual description first:

I am reading input from a text file (a list of words) and putting these words into an NSArray using componentsSeparatedByString method. This works.

But I wanted to select the words randomly and then delete them from the array so as to ensure a different word each time. Of course, you cannot change the NSArray contents. So...

I copied the contents of the NSArray into an NSMutableArray and use IT for the selection source. This also works - 269 objects in each array.

To return a word from the NSMutableArray I use the following code: note- the arrays are declared globally as

arrMutTextWords = [[NSMutableArray alloc] init]; //stack for words arrTextWords = [[NSArray alloc] init]; //permanent store for words

-(NSString*) getaTextWord {

// if the mutable text word array is empty refill

if ([arrMutTextWords count] == 0){

    for (int i = 0 ; i < [arrTextWords count]; i++) 
        [arrMutTextWords addObject:[arrTextWords objectAtIndex:i]];
}

int i = random() % [arrMutTextWords count];
NSString* ptrWord = [arrMutTextWords objectAtIndex:i];
[arrMutTextWords removeObjectAtIndex:i];
return ptrWord;

}

The program crashes during a call to the method above - here is the calling code: arrTmp is declared globally arrTmp = [[NSArray alloc] init]; //tmp store for words

for (int i = 0 ; i < 4; i++) {
    tmpWord = [self getaTextWord];
    [arrTmp addObject:tmpWord];
    [arrTmp addObject:tmpWord];
}

I'm thinking that somehow deleting strings from arrMutTextWords is invalidating the NSArray - but I can't think how this would occur.

+2  A: 

One possible source for problems is your fetching AND removing the NSString object from your list. Removing it releases that NSString instance therefore devalidating your reference.

To be shure to retain a reference you should use this code sequence instead:

NSString * ptrWord = [[[arrMutTextWords objectAtIndex:i] retain] autorelease];
[arrMutTextWords removeObjectAtIndex:i];
return ptrWord;

By the way: You should use

NSMutableArray *mutableArray = [NSMutableArray arrayWithArray: array];

instead of copying all values by hand. While i do not know the implementation of NSMutableArray, i know from times long ago (NeXTstep), that there are several possible optimizations that may speed up basic NSArray operations.

And finally copying this way is much more concise.

Ralf Edmund
Thanks very much for your prompt reply. I will check it out. Can you give me some info sources where i might read up on this issue?
There is a section on the memory Management behaviour for NSArray and NSMutableArray in the NSArray Class References which deals with this topic.Additional i would recommend the "Collections Programming Topics for Cocoa" which i read on a regular basis any time i'll get back from Java to Objective-C.
Ralf Edmund
You da man! I'm plugging in your code now.
It worked perfectly!!! It's obvious I need to bone up on memory management... I'll be checking out those references. Thanks again!
A: 

Just ran this through XCode and got random words returned, however I skipped the whole for loop and used addObjectsFromArrayfrom NSMutableArray.

NSArray *randomArray = [[NSArray alloc] initWithObjects:@"Paul", @"George", @"John", nil];
NSMutableArray *muteArray = [[NSMutableArray alloc] init];
[muteArray addObjectsFromArray:randomArray];

int i = random() % [muteArray count];
NSString* ptrWord = [muteArray objectAtIndex:i];
[muteArray removeObjectAtIndex:i];
NSLog(@"ptrWord %@", ptrWord); //gave me a different name each time I ran the function.

Hope this clears some things up.

Convolution
Yep that addObjectsFromArray is handy - I'll use it from now on.