SpokaneDude SpokaneDude - 23 days ago 5
Objective-C Question

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

Answer

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.