Reputation: 4974
I have two (2) classes defined in one .m file:
@interface vendorData : NSObject { // < first class
@public
NSString *vendor;
NSString *price;
NSString *condition;
}
@end
@implementation vendorData
@end
@interface DetailViewController () < UIAlertViewDelegate>
@end
@implementation DetailViewController // <-- second (main) class
// code for the main class follows
I initialize both the class and NSMutableArray like this:
NSMutableArray *arrayOfPrices = [[NSMutableArray alloc]initWithCapacity:100];
vendorData *data = [[vendorData alloc] init];
I fill the class data using NSScanner, then put the vendorData object into a NSMutableArray; this is how I'm populating the data object:
NSData *siteHTMLData = [NSData dataWithContentsOfURL: siteUrl];
siteHTMLData = [NSData dataWithContentsOfURL: siteUrl]; // get past first page ("searching")
NSString *htmlString = [[NSString alloc] initWithData:siteHTMLData encoding:NSUTF8StringEncoding];
// start the search
NSScanner *scanner = [[NSScanner alloc] initWithString:htmlString];
NSString *priceString, *vendorString, *conditionString;
vendorData *data = [[vendorData alloc]init];
do {
@try {
// find vendor
[scanner scanUpToString:@"<tr id=\"" intoString:nil];
scanner.scanLocation += 9;
[scanner scanUpToString: @"\r\n" intoString: &vendorString]; // find end of vendor
data->vendor = vendorString;
// find price
scanner.scanLocation += 2;
[scanner scanUpToString:@"<span >$" intoString:nil]; // find beginning of price
scanner.scanLocation += 8;
[scanner scanUpToString: @"</span>" intoString: &priceString]; // find end of price
data->price = priceString;
scanner.scanLocation += 7;
}
@catch (NSException *exception) {
if([[exception reason] isEqualToString: NSRangeException])
break;
}
// see if vendor/price is already in array; if so ignore it
NSLog(@"\ndata->vendor: %@,\n->price: %@", data->vendor, data->price); // <---------
[arrayOfPrices addObject:data]; // add struct to array
} while (([scanner isAtEnd] == NO) || (scanner.scanLocation > htmlString.length));
This is a portion of the log:
2014-08-24 11:53:03.154 BookInventoryManager[3741:60b] data->vendor: Thriftbooks.comUsed", ->price: 1.00 2014-08-24 11:53:03.155 BookInventoryManager[3741:60b] data->vendor: ValoreBooksUsed", ->price: 0.01 2014-08-24 11:53:03.155 BookInventoryManager[3741:60b]
and this is what the debugger shows in the arrayOfPrices array:
Amazon.ca.Marketplace should be the last entry added to arrayOfPrices, but for some reason it appears in each and every element of the mutable array. Why?
Upvotes: 0
Views: 37
Reputation: 45490
Every time you want to append a element you should create a new instance of the object.
You can create your own custom init to make it easier. Here is an example:
@interface vendorData : NSObject {
@public
NSString *vendor;
NSString *price;
NSString *condition;
}
-(id) initWithVendor:(NSString) vendor price:(NSString *)price condition:(NSString *) condition;
@end
@implementation vendorData
-(id) initWithVendor:(NSString) vendor price:(NSString *)price condition:(NSString *) condition{
self = [super init];
if(self) {
self.vendor = vendor;
self.price = price;
self.condition = condition;
}
return(self);
}
@end
And here is how you would fill your mutable array:
NSMutableArray *arrayOfPrices = [[NSMutableArray alloc]initWithCapacity:100];
vendorData *data1 = [[vendorData alloc] initWithVendor:@"Amazon" price:@"31.75" condition: nil];
[arrayOfPrices addObject:data1];
vendorData *data2 = [[vendorData alloc] initWithVendor:@"Ebay" price:@"20.00" condition: @"new"];
[arrayOfPrices addObject:data2];
EDIT: thank you for updating your post, all you need to do is move the object declaration inside of the do-while loop:
do {
vendorData *data = [[vendorData alloc]init];
@try {
...
or if you want to use the custom init in my example, use it at like this:
do {
@try {
// find vendor
[scanner scanUpToString:@"<tr id=\"" intoString:nil];
scanner.scanLocation += 9;
[scanner scanUpToString: @"\r\n" intoString: &vendorString]; // find end of vendor
// find price
scanner.scanLocation += 2;
[scanner scanUpToString:@"<span >$" intoString:nil]; // find beginning of price
scanner.scanLocation += 8;
[scanner scanUpToString: @"</span>" intoString: &priceString]; // find end of price
scanner.scanLocation += 7;
}
@catch (NSException *exception) {
if([[exception reason] isEqualToString: NSRangeException])
break;
}
// see if vendor/price is already in array; if so ignore it
vendorData *data = [[vendorData alloc] initWithVendor:vendorString price:priceString condition: nil];
NSLog(@"\ndata->vendor: %@,\n->price: %@", data->vendor, data->price);
[arrayOfPrices addObject:data]; // add struct to array
} while (([scanner isAtEnd] == NO) || (scanner.scanLocation > htmlString.length));
Upvotes: 1
Reputation: 52530
As with most problems, odds are that this is a bug in your code. That's what always should be your first thought, especially when you are doing something that thousands of people have done before: It's a bug in your code.
We don't have all the code. We have one line where you create a vendorData object. We don't see where you set the vendor and price. We have one line where you add a vendorData object to a mutable array, and we see that the mutable array contains the same object twice.
The most obvious explanation would be that you create a vendorData object once, then set vendor and price to different values, and always add the same vendorData object to the mutable array. Adding an object to a mutable array adds that object, not a copy of it.
Upvotes: 1