Adding Custom Object to NSMutableArray - objective-c

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'

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 by retaining 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 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:
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

Related

RestKit RKMappingResult gives [__NSCFBoolean length]: unrecognized selector sent to instance

I am fetching data from the New York Times Bestsellers JSON API using Reskit. I believe I have an issue with my attributes mapping. A typical JSON object that has to be fetched looks like the structure below. My code is also shown. The API call does return objects as matching the number of expected results but the RKMappingResult in the requestDataFromAPI method returns "[__NSCFBoolean length]: unrecognized selector sent to instance". I am not able to access them as printing Books gives nil. I am not sure what I'm doing wrong.
{
"status":"OK",
"copyright":"Copyright (c) 2016 The New York Times Company. All Rights Reserved.",
"num_results":10,
"last_modified":"2016-03-04T13:12:31-05:00",
"results":
{
"list_name":"Animals",
"bestsellers_date":"2016-02-27",
"published_date":"2016-03-13",
"display_name":"Animals",
"normal_list_ends_at":10,
"updated":"MONTHLY",
"books": [
{"rank":1,
"rank_last_week":0,
"weeks_on_list":0,
"asterisk":0,
"dagger":0,
"primary_isbn10":"0802123414",
"primary_isbn13":"9780802123411",
"publisher":"Grove Atlantic",
"description":"A grief-stricken British woman decides to raise a goshawk, a fierce bird that is notoriously difficult to tame.",
"price":0,
"title":"H IS FOR HAWK","author":"Helen Macdonald",
"contributor":"by Helen Macdonald",
"isbns": [
{"isbn10":"0802123414",
"isbn13":"9780802123411"
},
{"isbn10":"1448130727",
"isbn13":"9781448130726"
},
{"isbn10":"1481530968",
"isbn13":"9781481530965"
},
{"isbn10":"148153095X",
"isbn13":"9781481530958"
},
{"isbn10":"1410483614",
"isbn13":"9781410483614"
},
{"isbn10":"0802124739",
"isbn13":"9780802124739"
}]
}
}
- (void) initializeRestAPI
{
// Initialize RestKit using API base address
NSURL * baseURL = [NSURL URLWithString:#"http://api.nytimes.com"];
RKObjectManager * objectManager = [RKObjectManager managerWithBaseURL:baseURL];
// Initialize Core Data's managed object model from the bundle
NSManagedObjectModel * managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
// Initialize RestKit's managed object store
RKManagedObjectStore * managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
// Complete Core Data stack initialization via RestKit
[managedObjectStore createPersistentStoreCoordinator];
NSString * persistentStorePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"DataModel.sqlite"];
NSString * seedDatabasePath = [[NSBundle mainBundle] pathForResource:#"RKSeedDatabase" ofType:#"sqlite"];
NSError * error;
NSPersistentStore * persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:persistentStorePath fromSeedDatabaseAtPath:seedDatabasePath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
// Create RestKit's managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[self setupEntityMappingForObjectStore:managedObjectStore withObjectManager:objectManager];
[self requestDataFromAPI];
}
-(void) setupEntityMappingForObjectStore: (RKManagedObjectStore *) managedObjectStore withObjectManager: (RKObjectManager *) objectManager
{
RKEntityMapping * bookListMapping = [RKEntityMapping mappingForEntityForName:#"BookList" inManagedObjectStore:managedObjectStore];
bookListMapping.identificationAttributes = #[#"listName"];
[bookListMapping addAttributeMappingsFromDictionary:
#{#"results.list_name": #"listName",
#"results.bestsellers_date": #"bestsellersDate",
#"results.published_date": #"publishedDate",
#"results.display_name": #"displayName",
#"results.normal_list_ends_at": #"normalListEndsAt",
#"results.updated": #"updated"
}];
RKEntityMapping * bookMapping = [RKEntityMapping mappingForEntityForName:#"Book" inManagedObjectStore:managedObjectStore];
bookMapping.identificationAttributes = #[#"title"];
[bookMapping addAttributeMappingsFromDictionary:
#{#"rank": #"rank",
#"rank_last_week": #"rankLastWeek",
#"weeks_on_list": #"weeksOnList",
#"primary_isbn10": #"primaryIsbn10",
#"primary_isbn13": #"primaryIsbn13",
#"amazon_product_url": #"productUrl",
#"book_image": #"bookImage",
#"publisher": #"publisher",
#"description": #"bookDescription",
#"title": #"title",
#"contributor": #"contributor",
#"author": #"author",
#"price": #"price"
}];
[bookListMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"results.books" toKeyPath:#"books" withMapping:bookMapping]];
RKResponseDescriptor * bookListResponseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:bookListMapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"results.books"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
];
[objectManager addResponseDescriptor:bookListResponseDescriptor];
// Enable Activity Indicator Spinner
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
}
- (void)fetchBooksFromContext
{
NSManagedObjectContext * context = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSFetchRequest * fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"BookList"];
NSSortDescriptor * descriptor = [NSSortDescriptor sortDescriptorWithKey:#"listName" ascending:YES];
fetchRequest.sortDescriptors = #[descriptor];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
BookList * bookList = [fetchedObjects firstObject];
NSArray * books = [bookList.books allObjects];
//NSArray * books = [fetchedObjects firstObject];
NSLog(#"Books: %#",books);
}
- (void)requestDataFromAPI
{
NSDictionary * apiKeyData = [[NSUserDefaults standardUserDefaults] objectForKey:#"apiKeyData"];
NSString * apiKey = [apiKeyData objectForKey:#"apiKeyData"];
NSLog(#"requestDataFromAPI apiKey: %#",apiKey);
NSString * requestPath = [[NSString alloc] initWithFormat:#"/svc/books/v3/lists/%#?&api-key=%#",_categoryListName, apiKey];
[[RKObjectManager sharedManager]
getObjectsAtPath:requestPath
parameters:nil
success: ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
[self fetchBooksFromContext];
}
failure: ^(RKObjectRequestOperation *operation, NSError *error)
{
RKLogError(#"Loading from API failed with error: %#", error);
}
];
}
The core data object models are as shown
#import "BookList.h"
NS_ASSUME_NONNULL_BEGIN
#interface BookList (CoreDataProperties)
#property (nullable, nonatomic, retain) NSString *listName;
#property (nullable, nonatomic, retain) NSDate *bestsellersDate;
#property (nullable, nonatomic, retain) NSDate *publishedDate;
#property (nullable, nonatomic, retain) NSString *displayName;
#property (nullable, nonatomic, retain) NSNumber *normalListEndsAt;
#property (nullable, nonatomic, retain) NSString *updated;
#property (nullable, nonatomic, retain) NSSet<Book *> *books;
#end
#interface BookList (CoreDataGeneratedAccessors)
- (void)addBooksObject:(Book *)value;
- (void)removeBooksObject:(Book *)value;
- (void)addBooks:(NSSet<Book *> *)values;
- (void)removeBooks:(NSSet<Book *> *)values;
#end
NS_ASSUME_NONNULL_END
#import "Book.h"
NS_ASSUME_NONNULL_BEGIN
#interface Book (CoreDataProperties)
#property (nullable, nonatomic, retain) NSNumber *rankLastWeek;
#property (nullable, nonatomic, retain) NSNumber *weeksOnList;
#property (nullable, nonatomic, retain) NSString *primaryIsbn10;
#property (nullable, nonatomic, retain) NSString *primaryIsbn13;
#property (nullable, nonatomic, retain) NSString *productUrl;
#property (nullable, nonatomic, retain) NSString *bookImageUrl;
#property (nullable, nonatomic, retain) NSString *publisher;
#property (nullable, nonatomic, retain) NSString *bookDescription;
#property (nullable, nonatomic, retain) NSString *title;
#property (nullable, nonatomic, retain) NSString *contributor;
#property (nullable, nonatomic, retain) NSString *author;
#property (nullable, nonatomic, retain) NSNumber *price;
#end
NS_ASSUME_NONNULL_END

Get NSMutableDictionary from Singleton?

I created a singleton class in order to share an object inside my program. Here's the code:
SelectedRow.h
#import <Foundation/Foundation.h>
#import "TableEntry.h"
#interface SelectedRow : NSObject {
TableEntry *rowValue;
}
#property (nonatomic, retain) TableEntry *rowValue;
+ (id)sharedManager;
- (void)setVariable:(TableEntry*)value;
#end
and SelectedRow.m
#import "SelectedRow.h"
#import "TableEntry.h"
#implementation SelectedRow
#synthesize rowValue;
+ (id)sharedManager {
static SelectedRow *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
rowValue = [[TableEntry alloc] init];
}
return self;
}
- (void)setVariable:(TableEntry*)value {
rowValue = value;
}
#end
while TableEntry.h
#import <Foundation/Foundation.h>
#interface TableEntry : NSObject {
#private
NSString *videoId;
NSString *videoCategory;
NSString *videoTitle;
NSString *videoDescription;
NSDate *videoDate;
NSMutableArray *videoRelatedVideos;
NSDictionary *videoAdditionalInformation;
NSString *videoAccessControl;
NSArray *videoFields;
NSMutableDictionary *days;
NSMutableDictionary *views;
NSMutableDictionary *watchtime;
NSMutableDictionary *subscribers;
NSMutableDictionary *shares;
}
#property (copy) NSString *videoId;
#property (copy) NSString *videoCategory;
#property (copy) NSString *videoTitle;
#property (copy) NSString *videoDescription;
#property (copy) NSMutableArray *videoRelatedVideos;
#property (copy) NSDictionary *videoAdditionalInformation;
#property (copy) NSArray *videoFields;
#property (copy) NSString *videoAccessControl;
#property (copy) NSDate *videoDate;
#property (copy) NSMutableDictionary *days;
#property (copy) NSMutableDictionary *views;
#property (copy) NSMutableDictionary *subscribers;
#property (copy) NSMutableDictionary *shares;
#property (copy) NSMutableDictionary *watchtime;
- (id)setId:(NSString*)Id setCategory:(NSString*)Category setDate:(NSDate*)date setTitle:(NSString*)title setDescription:(NSString*)description setRelatedVideos:(NSMutableArray*)relatedVideos setAdditionalInformation:(NSDictionary*)additionalInformation setAccessControl:(NSString*)accessControl setFields:(NSArray*)fields setDays:(NSMutableDictionary*)days setViews:(NSMutableDictionary*)views setSubscribers:(NSMutableDictionary*)subscribers setShares:(NSMutableDictionary*)shares setWatchtime:(NSMutableDictionary*)watchtime;
- (NSString*)extractId;
- (NSString*)extractCategory;
- (NSString*)extractTitle;
- (NSString*)extractDescription;
- (NSMutableArray*)extractRelatedVideos;
- (NSDictionary*)extractAdditionalInformationVideos;
- (NSDictionary*)extractAccessControlVideos;
- (NSArray*)extractFields;
- (NSMutableDictionary*)extractDays;
- (NSMutableDictionary*)extractViews;
- (NSMutableDictionary*)extractSubscribers;
- (NSMutableDictionary*)extractShares;
- (NSMutableDictionary*)extractWatchtime;
#end
and TableEntry.m
- (id)init {
self = [super init];
if (self) {
videoId = #"9bZkp7q19f0";
videoCategory = #"Music";
videoTitle = #"Demo Title";
videoDescription = #"Demo description";
videoDate = [NSDate date];
videoAdditionalInformation = [NSDictionary alloc];
videoRelatedVideos = [NSMutableArray alloc];
videoAccessControl = #"demo accesControl";
videoFields = [NSArray alloc];
days = [NSMutableDictionary alloc];
views = [NSMutableDictionary alloc];
shares = [NSMutableDictionary alloc];
subscribers = [NSMutableDictionary alloc];
watchtime = [NSMutableDictionary alloc];
}
return self;
}
- (id)setId:(NSString*)Id setCategory:(NSString*)Category setDate:(NSDate*)date setTitle:(NSString*)title setDescription:(NSString*)description setRelatedVideos:(NSMutableArray*)relatedVideos setAdditionalInformation:(NSDictionary*)additionalInformation setAccessControl:(NSString*)accessControl setFields:(NSArray*)fields setDays:(NSMutableDictionary*)Days setViews:(NSMutableDictionary*)Views setSubscribers:(NSMutableDictionary*)Subscribers setShares:(NSMutableDictionary*)Shares setWatchtime:(NSMutableDictionary*)Watchtime {
videoId = Id;
videoCategory = Category;
videoDate = date;
videoTitle = title;
videoDescription = description;
videoRelatedVideos = relatedVideos;
videoAccessControl = accessControl;
videoAdditionalInformation = additionalInformation;
videoFields = fields;
days = Days;
views = Views;
subscribers = Subscribers;
watchtime = Watchtime;
shares = Shares;
return self;
}
- (NSString*)extractId {
return self.videoId;
}
- (NSString*)extractCategory{
return self.videoCategory;
}
- (NSString*)extractTitle{
return self.videoTitle;
}
- (NSString*)extractDescription{
return self.videoDescription;
}
- (NSMutableArray*)extractRelatedVideos{
return self.videoRelatedVideos;
}
- (NSString*)extractAccessControlVideos{
return self.videoAccessControl;
}
- (NSDictionary*)extractAdditionalInformationVideos{
return self.videoAdditionalInformation;
}
- (NSArray*)extractFields{
return self.videoFields;
}
- (NSMutableDictionary*)extractDays{
return self.days;
}
- (NSMutableDictionary*)extractSubscribers{
return self.subscribers;
}
- (NSMutableDictionary*)extractWatchtime{
return self.watchtime;
}
- (NSMutableDictionary*)extractShares{
return self.shares;
}
- (NSMutableDictionary*)extractViews{
return self.views;
}
#end
I can extract any values from the singleton with:
SelectedRow *selectedRow = [SelectedRow sharedManager];
NSString *videoID = [selectedRow.rowValue extractId];
the problem arises with any NSMutableDictionary. If I try:
SelectedRow *selectedRow = [SelectedRow sharedManager];
NSMutableDictionary *days = [selectedRow.rowValue extractDays];
or with any other NSMutableDictionary I get this error:
[NSMutableDictionary count]: method sent to an uninitialized mutable dictionary object
what I'm I doing wrong? Thanks
The [NSMutableDictionary alloc] call allocates the space for NSMutableDictionary, but it does not initialize it.
Replace it with [NSMutableDictionary dictionary] to fix the problem. Same goes for your NSArray and NSMutableArray objects (replace them with [NSMutable array] and [NSMutableArray array]).
The videoAdditionalInformation of type NSDictionary should be initialized to nil, though, because NSDictionary objects are immutable. If you are planning to set it to some dictionary later on, you might as well keep it nil on initialization.
In addition, you should reconsider the use of copy: it makes sense for NSString objects, but it hardly makes sense on NSMutableDictionary objects.

NSMutableArray can not add object?

I have 2 model:
#interface Program : NSObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, strong) NSMutableArray *guides;
#end
#interface Guide : NSObject
#property (nonatomic, retain) NSString *name;
#end
And I add some guides to program from one xml:
Program *program = [Program new];
program.name = #"My list"
for(DDXMLElement *guideElement in [programElement nodesForXPath:#"guide" error:&error])
{
Guide *guide = [Guide new];
guide.name = [guideElement stringValue];// [p attribute:#"name"];
[program.guides addObject:guide];
NSLog(#"load guide number: %d", [program.guides count]);
}
The out is always "load guide number: 0"
program.guides is nil, since you never created it.
In your Program's init method, add:
self.guides = [[NSMutableArray alloc] init];
Or, more sloppily, before your for loop add:
program.guides = [[NSMutableArray alloc] init];

Problem creating NSManagedObject derived class

I am doing something wrong here... I know that
I'm using Xcode and I have created the following class using the data modeller:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Project : NSManagedObject {
#private
}
#property (nonatomic, retain) NSNumber * indent;
#property (nonatomic, retain) NSNumber * collapsed;
#property (nonatomic, retain) NSString * color;
#property (nonatomic, retain) NSNumber * project_id;
#property (nonatomic, retain) NSNumber * item_order;
#property (nonatomic, retain) NSNumber * cache_count;
#property (nonatomic, retain) NSNumber * user_id;
#property (nonatomic, retain) NSString * name;
#end
When I am trying to propagate this class with data from a JSON source using the following code:
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"projects" ofType:#"json"];
if (filePath) {
NSString* jsonString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
DLog(#"JSON for Projects:%#", jsonString);
SBJsonParser* jsonParser = [SBJsonParser new];
id response = [jsonParser objectWithString:jsonString];
NSArray* array = (NSArray*) response;
NSEnumerator* e = [array objectEnumerator];
NSDictionary* dictionary;
while ((dictionary = (NSDictionary*)[e nextObject])) {
Project* project = [[Project alloc] init];
project.user_id = [dictionary objectForKey:#"user_id"];
project.name = [dictionary objectForKey:#"name"];
project.color = [dictionary objectForKey:#"color"];
project.collapsed = [dictionary objectForKey:#"collapsed"];
project.item_order = [dictionary objectForKey:#"item_order"];
project.cache_count = [dictionary objectForKey:#"cache_count"];
project.indent = [dictionary objectForKey:#"indent"];
project.project_id = [dictionary objectForKey:#"project_id"];
[elementArray addObject:project];
[project release];
}
}
However, the code stops at the project.user_id = [dictionary objectForKey:#"user_id"]; line with an exception "* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Project setUser_id:]: unrecognized selector sent to instance 0x590bcb0'"
I don't know why this is happening or how to resolve this.
I've set up a reality distortion field so I don't violate my NDA. And now I can answer your question, it has nothing to do with the product-that-must-not-be-named anyway.
There is your bug: Project* project = [[Project alloc] init];
The #dynamic setters and getters are not created for you if you create your object this way.
You can't use NSManagedObjects without a NSManagedObjectContext.
You should use something like this:
Project *project = (Project *)[NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:self.managedObjectContext];
Property names with underscores are not very sensible in the Objective C world - I guess the properties generated by Core Data have the wrong names therefore. Try using CamelCase, that is calling your properties userID, itemOrder, cacheCount etc.
You may need to set up your getters and setters.
It could be as simple as adding:
#synthesize user_id;
In your class file.

Does this copy class method leak memory?

- (id)copyWithZone:(NSZone *)zone {
PoolFacility *copy = [[[self class] allocWithZone:zone]init];
copy.name = [self.name copy];
copy.type = [self.type copy];
copy.phoneNumber = [self.phoneNumber copy];
//make sure I get proper copies of my dictionaries
copy.address = [self.address mutableCopy];
copy.webAddress = [self.webAddress copy];
copy.prices = [self.prices mutableCopy];
copy.pools = [self.pools mutableCopy];
return copy;
}
Can anyone see any memory leaks?
Here's the property types:
NSString *name;
NSString *type;
NSMutableDictionary *address;
NSString *phoneNumber;
NSString *webAddress;
NSMutableArray *prices;
NSMutableArray *pools;
Here are the property declarations:
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *type;
#property (nonatomic, copy) NSString *phoneNumber;
#property (nonatomic, retain) NSMutableDictionary *address;
#property (nonatomic, copy) NSString *webAddress;
#property (nonatomic, retain) NSMutableArray *prices;
#property (nonatomic, retain) NSMutableArray *pools;
The properties defined as copy and not retain will have an extra copy when set as below (your code)
copy.name = [self.name copy];
copy.type = [self.type copy];
copy.phoneNumber = [self.phoneNumber copy];
copy.webAddress = [self.webAddress copy];
it should be sufficient to only write them as
copy.name = self.name;
copy.type = self.type;
copy.phoneNumber = self.phoneNumber;
copy.webAddress = self.webAddress;
This almost certainly leaks like a sieve. You need to provide your #property and other method declarations for us to recommend the best way to fix it.