Adding Custom Object to NSMutableArray
Developing ios app. I have an object class Product.h and .m respectively along with my picker class which implements my vehicle selection to match products to vehicle. The files
product.h
#import <Foundation/Foundation.h>
@interface Product : NSObject {
}
@property (nonatomic, retain) NSString *iProductID;
@property (nonatomic, retain) NSString *vchProductCode;
@property (nonatomic, retain) NSString *vchPriceCode;
@property (nonatomic, retain) NSString *vchHitchUPC;
@property (nonatomic, retain) NSString *mHitchList;
@property (nonatomic, retain) NSString *mHitchMap;
@property (nonatomic, retain) NSString *fShippingWeight;
@property (nonatomic, retain) NSString *vchWC;
@property (nonatomic, retain) NSString *vchCapacity;
@property (nonatomic, retain) NSString *txtNote1;
@property (nonatomic, retain) NSString *txtNote2;
@property (nonatomic, retain) NSString *txtNote3;
@property (nonatomic, retain) NSString *txtNote4;
@property (nonatomic, retain) NSString *vchDrilling;
@property (nonatomic, retain) NSString *vchUPCList;
@property (nonatomic, retain) NSString *vchExposed;
@property (nonatomic, retain) NSString *vchShortDesc;
@property (nonatomic, retain) NSString *iVehicleID;
@property (nonatomic, retain) NSString *iProductClassID;
@property (nonatomic, retain) NSString *dtDateMod;
@property (nonatomic, retain) NSString *txtBullet1;
@property (nonatomic, retain) NSString *txtBullet2;
@property (nonatomic, retain) NSString *txtBullet3;
@property (nonatomic, retain) NSString *txtBullet4;
@property (nonatomic, retain) NSString *txtBullet5;
@property (nonatomic, retain) NSString *iUniqueIdentifier;
@property (nonatomic, retain) NSString *dtDateLastTouched;
@property (nonatomic, retain) NSString *txtNote6;
@property (nonatomic, retain) NSString *InstallTime;
@property (nonatomic, retain) NSString *SGID;
@property (nonatomic, retain) NSString *CURTID;
@property (nonatomic, retain) NSString *SGRetail;
@property (nonatomic, retain) NSString *SGMemPrice;
@property (nonatomic, retain) NSString *InstallSheet;
@property (nonatomic, retain) NSString *mHitchJobber;
@property (nonatomic, retain) NSString *CatID;
@property (nonatomic, retain) NSString *ParentID;
-(id) initWithDict:(NSDictionary *)dic;
-(NSString *) description;
@end
Product implementation .m
#import "Product.h"
@implementation Product
@synthesize iProductID;
@synthesize vchProductCode;
@synthesize vchPriceCode;
@synthesize vchHitchUPC;
@synthesize mHitchList;
@synthesize mHitchMap;
@synthesize fShippingWeight;
@synthesize vchWC;
@synthesize vchCapacity;
@synthesize txtNote1;
@synthesize txtNote2;
@synthesize txtNote3;
@synthesize txtNote4;
@synthesize vchDrilling;
@synthesize vchUPCList;
@synthesize vchExposed;
@synthesize vchShortDesc;
@synthesize iVehicleID;
@synthesize iProductClassID;
@synthesize dtDateMod;
@synthesize txtBullet1;
@synthesize txtBullet2;
@synthesize txtBullet3;
@synthesize txtBullet4;
@synthesize txtBullet5;
@synthesize iUniqueIdentifier;
@synthesize dtDateLastTouched;
@synthesize txtNote6;
@synthesize InstallTime;
@synthesize SGID;
@synthesize CURTID;
@synthesize SGRetail;
@synthesize SGMemPrice;
@synthesize InstallSheet;
@synthesize mHitchJobber;
@synthesize CatID;
@synthesize ParentID;
-(id) initWithDict:(NSDictionary *)dic
{
[super init];
//Initialize all variables
self.iProductID = [[NSString alloc] initWithString:[dic objectForKey:@"iProductID"]];
self.vchProductCode = [[NSString alloc] initWithString:[dic objectForKey:@"vchProductCode"]];
self.vchPriceCode = [[NSString alloc] initWithString:[dic objectForKey:@"vchPriceCode"]];
self.vchHitchUPC = [[NSString alloc] initWithString:[dic objectForKey:@"vchHitchUPC"]];
self.mHitchList = [[NSString alloc] initWithString:[dic objectForKey:@"mHitchList"]];
self.mHitchMap = [[NSString alloc] initWithString:[dic objectForKey:@"mHitchMap"]];
self.fShippingWeight = [[NSString alloc] initWithString:[dic objectForKey:@"fShippingWeight"]];
self.vc开发者_开发问答hWC = [[NSString alloc] initWithString:[dic objectForKey:@"vchWC"]];
self.vchCapacity = [[NSString alloc] initWithString:[dic objectForKey:@"vchCapacity"]];
self.txtNote1 = [[NSString alloc] initWithString:[dic objectForKey:@"txtNote1"]];
self.txtNote2 = [[NSString alloc] initWithString:[dic objectForKey:@"txtNote2"]];
self.txtNote3 = [[NSString alloc] initWithString:[dic objectForKey:@"txtNote3"]];
self.txtNote4 = [[NSString alloc] initWithString:[dic objectForKey:@"txtNote4"]];
self.vchDrilling = [[NSString alloc] initWithString:[dic objectForKey:@"vchDrilling"]];
self.vchUPCList = [[NSString alloc] initWithString:[dic objectForKey:@"vchUPCList"]];
self.vchExposed = [[NSString alloc] initWithString:[dic objectForKey:@"vchExposed"]];
self.vchShortDesc = [[NSString alloc] initWithString:[dic objectForKey:@"vchShortDesc"]];
self.iVehicleID = [[NSString alloc] initWithString:[dic objectForKey:@"iVehicleID"]];
self.iProductClassID = [[NSString alloc] initWithString:[dic objectForKey:@"iProductClassID"]];
self.dtDateMod = [[NSString alloc] initWithString:[dic objectForKey:@"dtDateMod"]];
self.txtBullet1 = [[NSString alloc] initWithString:[dic objectForKey:@"txtBullet1"]];
self.txtBullet2 = [[NSString alloc] initWithString:[dic objectForKey:@"txtBullet2"]];
self.txtBullet3 = [[NSString alloc] initWithString:[dic objectForKey:@"txtBullet3"]];
self.txtBullet4 = [[NSString alloc] initWithString:[dic objectForKey:@"txtBullet4"]];
self.txtBullet5 = [[NSString alloc] initWithString:[dic objectForKey:@"txtBullet5"]];
self.iUniqueIdentifier = [[NSString alloc] initWithString:[dic objectForKey:@"iUniqueIdentifier"]];
self.dtDateLastTouched = [[NSString alloc] initWithString:[dic objectForKey:@"dtDateLastTouched"]];
self.txtNote6 = [[NSString alloc] initWithString:[dic objectForKey:@"txtNote6"]];
self.InstallTime = [[NSString alloc] initWithString:[dic objectForKey:@"InstallTime"]];
self.SGID = [[NSString alloc] initWithString:[dic objectForKey:@"SGID"]];
self.CURTID = [[NSString alloc] initWithString:[dic objectForKey:@"CURTID"]];
self.SGRetail = [[NSString alloc] initWithString:[dic objectForKey:@"SGRetail"]];
self.SGMemPrice = [[NSString alloc] initWithString:[dic objectForKey:@"SGMemPrice"]];
self.InstallSheet = [[NSString alloc] initWithString:[dic objectForKey:@"InstallSheet"]];
self.mHitchJobber = [[NSString alloc] initWithString:[dic objectForKey:@"mHitchJobber"]];
self.CatID = [[NSString alloc] initWithString:[dic objectForKey:@"CatID"]];
self.ParentID = [[NSString alloc] initWithString:[dic objectForKey:@"ParentID"]];
return self;
}
-(NSString *) description
{
return [NSString stringWithFormat:@"iProductID = %@\n vchProductCode = %@\n vchPriceCode = %@\n vchHitchUPC = %@\n mHitchList = %@\n mHitchMap = %@\n fShippingWeight = %@\n vchWC = %@\n vchCapacity = %@\n txtNote1 = %@\n txtNote2 = %@\n txtNote3 = %@\n txtNote4 = %@\n vchDrilling = %@\n vchUPCList = %@\n vchExposed = %@\n vchShortDesc = %@\n iVehicleID = %@\n iProductClassID = %@\n dtDateMod = %@\n txtBullet1 = %@\n txtBullet2 = %@\n txtBullet3 = %@\n txtBullet4 = %@\n txtBullet4 = %@\n txtBullet5 = %@\n iUniqueIdentifier = %@\n dtDateLastTouched = %@\n txtNote6 = %@\n InstallTime = %@\n SGID = %@\n CURTID = %@\n SGRetail = %@\n SGMemPrice = %@\n InstallSheet = %@\n mHitchJobber = %@\n CatID = %@\n ParentID = %@\n", iProductID, vchProductCode, vchPriceCode, vchHitchUPC, mHitchList, mHitchMap, fShippingWeight, vchWC, vchCapacity, txtNote1, txtNote2, txtNote3, txtNote4, vchDrilling, vchUPCList, vchExposed, vchShortDesc, iVehicleID, iProductClassID, dtDateMod, txtBullet1, txtBullet2, txtBullet3, txtBullet4,txtBullet5, iUniqueIdentifier, dtDateLastTouched,txtNote6,InstallTime,SGID,CURTID,SGRetail,SGMemPrice,InstallSheet,mHitchJobber,CatID, ParentID];
}
@end
Ignoring the fact that its really long I also tried to just set the property but then my product didnt have any values. So I alloc'd for all properties, not sure which is "correct"
the use of product picker.h
#import <UIKit/UIKit.h>
@class Vehicle;
@class Product;
@interface Picker : UITableViewController <NSXMLParserDelegate> {
NSString *currentRow;
NSString *currentElement;
Vehicle *vehicle;
}
@property (nonatomic, retain) NSMutableArray *dataArray;
//@property (readwrite, copy) NSString *currentRow;
//@property (readwrite, copy) NSString *currentElement;
-(void) getYears:(NSString *)string;
-(void) getMakes:(NSString *)year;
-(void) getModels:(NSString *)year: (NSString *)make;
-(void) getStyles:(NSString *)year: (NSString *)make: (NSString *)model;
-(void) getHitch:(NSString *)year: (NSString *)make: (NSString *)model: (NSString *)style;
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
@end
The implementation .m
#import "Product.h"
#import "Picker.h"
#import "KioskAppDelegate.h"
#import "JSON.h"
#import "Vehicle.h"
@implementation Picker
@synthesize dataArray;
-(void) getHitch:(NSString *)year: (NSString *)make: (NSString *)model: (NSString *)style{
currentRow = [NSString stringWithString:@"z:row"];
currentElement = [NSString stringWithString:@"gethitch"];
//Reinitialize data array
[self.dataArray removeAllObjects];
[self.dataArray release];
self.dataArray = [[NSArray alloc] initWithObjects:nil];
//Build url & string
NSString *thisString = [[NSString alloc] initWithString:@""];
thisString = [NSString stringWithFormat:@"http://api.curthitch.biz/AJAX_CURT.aspx?action=GetHitch&dataType=json&year=%@&make=%@&model=%@&style=%@",year,make,model,style];
//Request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:thisString]];
//Perform request and fill data with json
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
//Get string from data
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
//set up parser
SBJsonParser *parser = [[SBJsonParser alloc] init];
//parse json into object
NSArray *tempArray = [parser objectWithString:json_string error:nil];
for (NSDictionary *dic in tempArray) {
Product *tempProduct = [[Product alloc] initWithDict:dic];
NSLog(@"is tempProduct valid %@", (tempProduct) ? @"YES" : @"NO");
[self.dataArray addObject:tempProduct];
}
}
@end
So I stripped out all the table methods and misc crap that doesnt matter. In the end my problem is adding the "tempProduct" object to the mutable array dataArray so that I can customize the table cells. Using the json framework im parsing out some json which returns an array of NSDictionary objects. Stepping through that my dictionary objects look good, I populate my custom object with properties for all my fields which goes through fine, and the values look right. However I cant add this to the array, I've tried several different implementations doesn't work. Not sure what I'm doing wrong. In some instances doing a po tempProduct prints the description and sometimes it does not. same with right clicking on the variable and choosing print description.
Actual error message
2011-02-22 15:53:56.058 Kiosk[8547:207] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x4e1ba40
2011-02-22 15:53:56.060 Kiosk[8547:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x4e1ba40'
*** Call stack at first throw:
(
0 CoreFoundation 0x00dbabe9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f0f5c2 objc_exception_throw + 47
2 CoreFoundation 0x00dbc6fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d2c366 ___forwarding___ + 966
4 CoreFoundation 0x00d2bf22 _CF_forwarding_prep_0 + 50
5 Kiosk 0x00003ead -[Picker getHitch::::] + 1091
6 Kiosk 0x00003007 -[Picker tableView:didSelectRowAtIndexPath:] + 1407
7 UIKit 0x0009b794 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
8 UIKit 0x00091d50 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 219
9 Foundation 0x007937f6 __NSFireDelayedPerform + 441
10 CoreFoundation 0x00d9bfe3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
11 CoreFoundation 0x00d9d594 __CFRunLoopDoTimer + 1220
12 CoreFoundation 0x00cf9cc9 __CFRunLoopRun + 1817
13 CoreFoundation 0x00cf9240 CFRunLoopRunSpecific + 208
14 CoreFoundation 0x00cf9161 CFRunLoopRunInMode + 97
15 GraphicsServices 0x0102e268 GSEventRunModal + 217
16 GraphicsServices 0x0102e32d GSEventRun + 115
17 UIKit 0x0003442e UIApplicationMain + 1160
18 Kiosk 0x0000239a main + 104
19 Kiosk 0x00002329 start + 53
)
terminate called after throwing an instance of 'NSException'
Your problem is this:
self.dataArray = [[NSArray alloc] initWithObjects:nil];
There are a couple things wrong here:
- This is a memory leak. The property is declared as a
retain
property, and you're giving it an owned object. Therefore you've declared ownership of the object twice (once with+alloc
, then again byretaining
it in the property setter method), but you only relinquish ownership once (when the object is deallocated). - You're not giving
self
a mutable array. You're giving it an immutable array. In other words,NSArray != NSMutableArray
. Once you've created anNSArray
, you cannot change its contents. You can only do that with anNSMutableArray
.
To fix this, you should change the line to:
self.dataArray = [NSMutableArray array];
Beyond this, you have memory leaks all over the place.
For example, pretty much every single line in your
-[Product initWithDict:]
method is leaking memory. They should all be replaced with:self.propertyName = [dic objectForKey:@"dictionary key"];
This is flat-out wrong:
[self.dataArray release];
You should do:
self.dataArray = nil;
This is another leak:
NSString *thisString = [[NSString alloc] initWithString:@""]; thisString = [NSString stringWithFormat:@"http://api.curthitch.biz/AJAX_CURT.aspx?action=GetHitch&dataType=json&year=%@&make=%@&model=%@&style=%@",year,make,model,style];
You should do:
NSString *thisString = [NSString stringWithFormat:@"http://api.curthitch.biz/AJAX_CURT.aspx?action=GetHitch&dataType=json&year=%@&make=%@&model=%@&style=%@",year,make,model,style];
you
+alloc
a string referenced byjson_string
, but you neverrelease
it.- you
+alloc
anSBJsonParser
, but you neverrelease
it. - you
+alloc
aProduct
on each iteration of yourfor
loop, but you neverrelease
it.
It's pretty clear that you haven't read some of the fundamental documentation. I strongly suggest that you do:
- The Objective-C Programming Language Reference
- The Memory Management Programming Guide
- Naming Conventions
- Everything you need to know about pointers in C (boredzo.org)
Your problem is that you allocate an NSArray and not an NSMutableArray in your assignment to self.dataArray. Try [[NSMutableArray alloc] init]
Also, if you alloc / init objects, and then use a retain, you will over-retain your objects. Autorelease them at the time of assignment
精彩评论