Search code examples
objective-cnsmutablearraynsarray

Why does NSMutableArray have duplicate objects?


I have some code that creates a string and adds that string to a mutable array. Here is the code:

    ExportBookData *abe = [[ExportBookData alloc] initWithCategory:@"ABE"];
    abe.builtFileList = [[NSMutableDictionary alloc] initWithCapacity: 2];
    abe.exportData = [NSMutableArray array];  

        for(int i = 0; i < booksArray.count; i++)  {
        [tabString setString: @""];  //   clear it...
        [tabString appendString:[NSString stringWithFormat:@"%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t"
                                 "%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\n",

                                 [[booksArray objectAtIndex:i] sku],
                                 [[booksArray objectAtIndex:i] title],
                                 [[booksArray objectAtIndex:i] author],
                                 [[booksArray objectAtIndex:i] illustrator],
                                 [[booksArray objectAtIndex:i] price],
                                 [(Books *)[booksArray objectAtIndex:i] quantity],
                                 @"Book",  //  book type
                                 [[booksArray objectAtIndex:i] bookDescription],
                                 [[booksArray objectAtIndex:i] binding],
                                 [[booksArray objectAtIndex:i] bookCondition],
                                 [[booksArray objectAtIndex:i] pubName],
                                 [[booksArray objectAtIndex:i]pubLocation ],
                                 [[booksArray objectAtIndex:i] pubYear],
                                 [[booksArray objectAtIndex:i] isbn],
                                 [[booksArray objectAtIndex:i] primaryCatalog],
                                 @"",@"",  //  seller catalogs  secondary and third catalog entries (not used)
                                 @"",  //  ABE category    <----- TODO
                                 [[booksArray objectAtIndex:i] keywords],
                                 [[booksArray objectAtIndex:i] jacket],
                                 [[booksArray objectAtIndex:i] edition],
                                 [[booksArray objectAtIndex:i] printing],
                                 [[booksArray objectAtIndex:i] signedBy],
                                 [[booksArray objectAtIndex:i]volume],
                                 [[booksArray objectAtIndex:i] bookSize],
                                 @""  //  image url
                                 ]];

        NSLog(@"\n\ntabString: %@",tabString);

        [abe.exportData addObject: tabString];  //  add to array

        NSLog(@"\n\nexportData: %@", abe.exportData);  //  <-------------- overwritten with last entry, so all entries are the same  TODO
    }

booksArray is a NSMutableArray which is filled by reading a CoreData store; exportData is also a NSMutableArray. The data in booksArray is valid, with a count of 2; the data in tabString is also valid, containing the correct line from booksArray. The line

[abe.exportData addObject: tabString];

has a duplication of the last record in booksArray. This is the output from the log methods:

---->booksArray.count: 2

tabString: 120  Women Who Run With The Wolves:  Myths And Stories Of The Wild Woman Archetype   Clarissa Pinkola Estes      2.1 1   Book        Hardcover       Ballantine Books        1992    0345377443                      Like New        (null)              

exportData: (
"120\tWomen Who Run With The Wolves:  Myths And Stories Of The Wild Woman Archetype\tClarissa Pinkola Estes\t\t2.1\t1\tBook\t\tHardcover\t\tBallantine Books\t\t1992\t0345377443\t\t\t\t\t\tLike New\t\t(null)\t\t\t\t\n"
)

tabString: 121  Colossus: The Secrets Of Bletchley Park's Code-breaking Computers   B. Jack Copeland        35  1   Book        Paperback (Reprint)     Oxford University Press, USA        2010    9780199578146                       No Dust Jacket      (null)              

exportData: (
"121\tColossus: The Secrets Of Bletchley Park's Code-breaking Computers\tB. Jack Copeland\t\t35\t1\tBook\t\tPaperback (Reprint)\t\tOxford University Press, USA\t\t2010\t9780199578146\t\t\t\t\t\tNo Dust Jacket\t\t(null)\t\t\t\t\n",
"121\tColossus: The Secrets Of Bletchley Park's Code-breaking Computers\tB. Jack Copeland\t\t35\t1\tBook\t\tPaperback (Reprint)\t\tOxford University Press, USA\t\t2010\t9780199578146\t\t\t\t\t\tNo Dust Jacket\t\t(null)\t\t\t\t\n"
)

I have looked and looked (Google, SO) for several hours now, and I am doing everything correctly, from what I see in other question's answers, and I don't see what could possibly cause this. Help would greatly be appreciated. SD


Solution

  • Your tabString appears to be an NSMutableString that you attempt to use over and over. That doesn't work. You end up added the same mutable string to the array multiple times. Just assign the stringWithFormat to a normal, local NSString.

    And why call [booksArray objectAtIndex:i] over and over and over? Get the object once. Better yet, use fast enumeration in your loop.

    for (YourBookClass *book in booksArray) {
        NSString *tabString = [NSString stringWithFormat:@"%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t"
                                 "%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\t%@\n",
           book.sku,
           book.title,
           // and all of the rest of the properties
           ]];
    
        [abe.exportData addObject:tabString];
    }
    

    Also keep in mind that your code will generate an invalid CSV file if any the values contain a tab or newline character. Such values need to be put into quotes.