0

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.vchWC = [[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'

2 Answers 2

6

Your problem is this:

self.dataArray = [[NSArray alloc] initWithObjects:nil];

There are a couple things wrong here:

  1. 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 by retaining it in the property setter method), but you only relinquish ownership once (when the object is deallocated).
  2. You're not giving self a mutable array. You're giving it an immutable array. In other words, NSArray != NSMutableArray. Once you've created an NSArray, you cannot change its contents. You can only do that with an NSMutableArray.

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 by json_string, but you never release it.

  • you +alloc an SBJsonParser, but you never release it.
  • you +alloc a Product on each iteration of your for loop, but you never release it.

It's pretty clear that you haven't read some of the fundamental documentation. I strongly suggest that you do:

Sign up to request clarification or add additional context in comments.

8 Comments

Or - don't call self in the initialiser. i.e dataArray = [[NSMutabelArray alloc] init];. But remember to release it in the dealloc
@Abizern yes, that is sound advice. My answer, while technically not best practice, was intended to change the least amount of stuff with his code. (It's likely easier for him to understand things that way)
NP. But he's going to be seeing a lot of example code written in this way, so it makes sense to mention it.
And - get into the habit of declaring properties for NSString, NSArray, NSSet, NSDictionary as copy rather than retain. These classes are parts of class clusters where they have a mutable counterpart (NSMutableString, NSMutableArray, NSMutableSet, NSMutableDictionary). If, for some reason you are passed a mutable version which is changed by another object then the state of your object has changed without you knowing about it. Setting properties to be copies prevents this from happening.
@Abizern: unless you have a property that you specifically want the mutable variant as the type. declaring it as copy would break that, because the setter invokes -copy (resulting in the immutable variant), as opposed to -mutableCopy.
|
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.