I would like to persist an object of a class (not just NSString´s). For instance, I have this class:
** News.h:**
#import <Foundation/Foundation.h>
#interface News : NSObject
#property (nonatomic, retain) NSString * atrib1;
#property (nonatomic, retain) NSString * atrib2;
#end
** News.m:**
#import "News.h"
#implementation News
#synthesize atrib1;
#synthesize atrib2;
#end
Should I have to use a plist to storage it? How should I do it?
Using NSCoding:
In News.m, I have added:
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:atrib1 forKey:#"key1"];
[encoder encodeObject:atrib2 forKey:#"key2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
atrib1 = [[decoder decodeObjectForKey:#"key1"] retain];
atrib2 = [[decoder decodeObjectForKey:#"key2"] retain];
return self;
}
-(void)dealloc{
[super dealloc];
[atrib1 release];
[atrib2 release];
}
In News.h:
#interface News : NSObject<NSCoding>{
NSCoder *coder;
}
#property (nonatomic, retain) NSString * atrib1;
#property (nonatomic, retain) NSString * atrib2;
#end
To read update and persist a new object in the plist:
- (IBAction)addANewNews:(id)sender {
//Plist File
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"myplist.plist"];
//Reading current news
NSData *oldNews = [NSData dataWithContentsOfFile:plistPath];
NSMutableArray *news = (NSMutableArray *)[NSKeyedUnarchiver unarchiveObjectWithData:oldNews];
if (news == nil)
news = [[NSMutableArray alloc] init];
//Adding a new news
[news addObject:aNewNews];
NSError *error;
NSData* newData = [NSKeyedArchiver archivedDataWithRootObject:news];
//persisting the updated news
BOOL success =[newData writeToFile:plistPath options:NSDataWritingAtomic error:&error];
if (!success) {
NSLog(#"Could not write file.");
}else{
NSLog(#"Success");
}
}
Related
I have one tables looks like as below
I have one XML where detail of CLUB is available. Every tag has one value but Images tag contain dynamic images.
After this my object looks like as below
ClubDetails.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "ClubDetailsImages.h"
#interface ClubDetails : NSManagedObject
#property (nonatomic, retain) NSString * clubarea;
#property (nonatomic, retain) NSString * clubdealhere;
#property (nonatomic, retain) NSString * clubdescription;
#property (nonatomic, retain) NSString * clubdistance;
#property (nonatomic, retain) NSString * clubemail;
#property (nonatomic, retain) NSString * clubfacility;
#property (nonatomic, retain) NSString * clubfav;
#property (nonatomic, retain) NSString * clubid;
#property (nonatomic, retain) NSString * clublat;
#property (nonatomic, retain) NSString * clublogopath;
#property (nonatomic, retain) NSString * clubname;
#property (nonatomic, retain) NSString * clubphone;
#property (nonatomic, retain) NSString * cluburl;
#property (nonatomic, retain) NSString * clubvenutype;
#property (nonatomic, retain) NSString * clublong;
#property (nonatomic, retain) NSSet *clubdetailsimages;
#end
#interface ClubDetails (CoreDataGeneratedAccessors)
- (void)addClubdetailsimagesObject:(ClubDetailsImages *)value;
- (void)removeClubdetailsimagesObject:(ClubDetailsImages *)value;
- (void)addClubdetailsimages:(NSSet *)value;
- (void)removeClubdetailsimages:(NSSet *)value;
Its .m files looks like as below
#implementation ClubDetails
#dynamic clubarea;
#dynamic clubdealhere;
#dynamic clubdescription;
#dynamic clubdistance;
#dynamic clubemail;
#dynamic clubfacility;
#dynamic clubfav;
#dynamic clubid;
#dynamic clublat;
#dynamic clublogopath;
#dynamic clubname;
#dynamic clubphone;
#dynamic cluburl;
#dynamic clubvenutype;
#dynamic clublong;
#dynamic clubdetailsimages;
- (void)addClubdetailsimagesObject:(ClubDetailsImages *)value {
NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
[self willChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
[[self primitiveValueForKey:#"ClubDetailsImages"] addObject:value];
[self didChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
}
- (void)removeClubdetailsimagesObject:(ClubDetailsImages *)value {
NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
[self willChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
[[self primitiveValueForKey:#"ClubDetailsImages"] removeObject:value];
[self didChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
}
- (void)addClubdetailsimages:(NSSet *)value {
[self willChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
[[self primitiveValueForKey:#"ClubDetailsImages"] unionSet:value];
[self didChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
}
- (void)removeClubdetailsimages:(NSSet *)value {
[self willChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
[[self primitiveValueForKey:#"ClubDetailsImages"] minusSet:value];
[self didChangeValueForKey:#"ClubDetailsImages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
}
***ClubDetailsImages.h*** looks like
#class ClubDetails;
#interface ClubDetailsImages : NSManagedObject
#property (nonatomic, retain) NSString * images;
#property (nonatomic, retain) ClubDetails *clubdetailed;
***ClubDetailsImages.m*** looks like
#implementation ClubDetailsImages
#dynamic images;
#dynamic clubdetailed;
For Saving, I wrote code like this
-(void)saveClubDetails:(NSMutableArray*)allClubs{
NSError *error;
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"ClubDetails" inManagedObjectContext:context]];
[fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSArray *allObject = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject * obj in allObject) {
[context deleteObject:obj];
}
NSError *saveError = nil;
[context save:&saveError]; // NO MORE VALUE IS DB
for (int x = 0; x<[allClubs count]; x++) {
ClubDetails *club = [NSEntityDescription insertNewObjectForEntityForName:#"ClubDetails"
inManagedObjectContext:context];
ClubDetails2 *ob = (ClubDetails2*)[allClubs objectAtIndex:x];
club.clubarea = [NSString stringWithFormat:#"%#", ob.clubarea];
club.clubdealhere = [NSString stringWithFormat:#"%#", ob.clubdealhere];
club.clubdescription = [NSString stringWithFormat:#"%#", ob.clubdescription];
club.clubdistance = [NSString stringWithFormat:#"%#", ob.clubdistance];
club.clubemail = [NSString stringWithFormat:#"%#", ob.clubemail];
club.clubfacility = [NSString stringWithFormat:#"%#", ob.clubfacility];
club.clubfav = [NSString stringWithFormat:#"%#", ob.clubfav];
club.clubid = [NSString stringWithFormat:#"%#", ob.clubid];
club.clublat = [NSString stringWithFormat:#"%#", ob.clublat];
club.clublogopath = [NSString stringWithFormat:#"%#", ob.clublogopath];
club.clubname = [NSString stringWithFormat:#"%#", ob.clubname];
club.clubphone = [NSString stringWithFormat:#"%#", ob.clubphone];
club.cluburl = [NSString stringWithFormat:#"%#", ob.cluburl];
club.clubvenutype = [NSString stringWithFormat:#"%#", ob.clubvenutype];
club.clublong = [NSString stringWithFormat:#"%#", ob.clublong];
ClubDetailsImages *clubImages = [NSEntityDescription insertNewObjectForEntityForName:#"ClubDetailsImages"
inManagedObjectContext:context];
clubImages.images = [NSString stringWithFormat:#"veer url image"];
[club addClubdetailsimagesObject:clubImages];
}
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
// NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Clubs"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedArray = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"COUNT of arary is %d", [fetchedArray count]);
for (Clubs *info in fetchedArray) {
NSLog(#" Duaan Name ~~~~ : %#", info.clubname);
}
}
I AM STUCK IN FOLLOWING POINTS
1. How to save such objects in CoreData where one club may be 3, 4, 5 images which are stored in Array?
2. How can I fetch that one-to-more relationship from CoreData?
Just keep adding the objects and linking them to the ClubDetails, e.g.given that you have an array of image strings from somewhere....
for (NSString *image in images)
{
ClubDetailsImages *clubImages = [NSEntityDescription insertNewObjectForEntityForName:#"ClubDetailsImages" inManagedObjectContext:context];
clubDetailsImages.image = image;
clubDetailsImages.clubdetailed = club;
}
Not sure exactly what you asking here, but given a ClubDetails instance:
NSSet *images = club.clubdetailsimages;
Also, why have you implemented addClubdetailsimagesObject etc. This is not required. Use XCode to generate your entity classes and you will see that these methods are not created.
I have a plist which I read from my bundle into a new plist object that I put in the root directory for reading and writing. My question is what do I do with this or what dose the application do when its quit, and better yet what happens when the app is killed from the "multi task" menu from ios.
Also is there a way to save this plist to memory/the bundle for future use when the application is used again.
My code is as follows for refrence.
Here is my .h
#import <Foundation/Foundation.h>
#interface EngineProperties : NSObject {
NSString *signature;
NSNumber *version;
NSNumber *request;
NSNumber *dataVersion;
NSMutableDictionary *cacheValue;
//cachevalue Items
NSNumber *man;
NSNumber *mod;
NSNumber *sub;
}
#property (copy, nonatomic) NSString *signature;
#property (copy, nonatomic) NSNumber *version;
#property (copy, nonatomic) NSNumber *request;
#property (copy, nonatomic) NSNumber *dataVersion;
#property (copy, nonatomic) NSMutableDictionary *cacheValue;
//cachevalue Items
#property (copy, nonatomic) NSNumber *man;
#property (copy, nonatomic) NSNumber *mod;
#property (copy, nonatomic) NSNumber *sub;
//Singletton
+ (id)sharedManager;
- (void) saveData:(NSString *)methodName signature:(NSString *)pSignature Version:(NSNumber *)pVersion request:(NSNumber *)rNumber dataVersion:(NSNumber *)dvReturned cacheValue:(NSNumber *)cValue;
#end
and Here is my .m
#import "EngineProperties.h"
static EnginePropertiesController *sharedMyManager = nil;
#implementation EngineProperties
#synthesize signature;
#synthesize version;
#synthesize request;
#synthesize dataVersion;
#synthesize cacheValue;
#synthesize man;
#synthesize mod;
#synthesize sub;
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
// Data.plist code
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"EngineProperties.plist"];
// check to see if Data.plist exists in documents
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
// if not in documents, get property list from main bundle
plistPath = [[NSBundle mainBundle] pathForResource:#"EngineProperties" ofType:#"plist"];
}
// read property list into memory as an NSData object
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
// convert static property liost into dictionary object
NSDictionary *tempRoot = (NSMutableDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
if (!tempRoot)
{
NSLog(#"Error reading plist: %#, format: %d", errorDesc, format);
}
// assign values
self.signature = [tempRoot objectForKey:#"Signature"];
self.version = [tempRoot objectForKey:#"Version"];
self.request = [tempRoot objectForKey:#"Request"];
self.dataVersion = [tempRoot objectForKey:#"Data Version"];
man = [cacheValue objectForKey:#"Man"];
mod = [cacheValue objectForKey:#"Mod"];
sub = [cacheValue objectForKey:#"SubMod"];
cacheValue = [tempRoot objectForKey:#"Cache Value"];
}
- (void) saveData:(NSString *)methodName signature:(NSString *)pSignature Version:(NSNumber *)pVersion request:(NSNumber *)rNumber dataVersion:(NSNumber *)dvReturned cacheValue:(NSNumber *)cValue;
{
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"EngineProperties.plist"];
// set the variables to the values in the text fields
self.signature = pSignature;
self.version = pVersion;
self.request = rNumber;
self.dataVersion = dvReturned;
//do some if statment stuff here to put the cache in the right place or what have you.
if (methodName == #"manufacturers")
{
self.man = cValue;
}
else if (methodName == #"models")
{
self.mod = cValue;
}
else if (methodName == #"subMod")
{
self.sub = cValue;
}
self.cacheValue = [NSDictionary dictionaryWithObjectsAndKeys:
man, #"Manufacturers",
mod, #"Models",
sub, #"SubModels", nil];
NSDictionary *plistDict = [NSDictionary dictionaryWithObjectsAndKeys:
signature, #"Signature",
version, #"Version",
request, #"Request",
dataVersion, #"Data Version",
cacheValue, #"Cache Value", nil];
NSString *error = nil;
// create NSData from dictionary
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// check is plistData exists
if(plistData)
{
// write plistData to our Data.plist file
[plistData writeToFile:plistPath atomically:YES];
NSString *myString = [[NSString alloc] initWithData:plistData encoding:NSUTF8StringEncoding];
// NSLog(#"%#", myString);
}
else
{
NSLog(#"Error in saveData: %#", error);
// [error release];
}
}
#end
It honestly depends on how frequently you'll be asking for and changing the plist's values. For instance, my app only needed to retrieve it once, then write it a few times (nothing much), so all of my saving code was at the end of said particular method.
However, if your plist is live (constant value changes), keeping a reference to the data you wish to save that is accessible from the AppDelegate is recommended. That way, you can simply call: beginBackgroundTaskWithExpirationHandler: on -applicationDidResignActive and save your plist data.
(Note, if the user is fast enough to kill your app before it saves completely (big if), there are no guarantees as to the integrity of your plist).
follow the blow link in that link they provided the code also. How to Write/Read data to .plist file.
Plist
You can quickly and easily save plists to NSUserDefaults
Check out this quick tutorial:
http://www.cocoadev.com/index.pl?NSUserDefaults
I have made a very simple custom object pictureData.
Here is the .h file
#import <Foundation/Foundation.h>
#interface pictureData : NSObject {
NSString *fileName;
NSString *photographer;
NSString *title;
NSString *license;
}
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) NSString *photographer;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *license;
+(pictureData*)picDataWith:(NSDictionary*)dictionary;
#end
The .m file
#import "pictureData.h"
#implementation pictureData
#synthesize fileName;
#synthesize photographer;
#synthesize title;
#synthesize license;
+ (pictureData*)picDataWith:(NSDictionary *)dictionary {
pictureData *tmp = [[[pictureData alloc] init] autorelease];
tmp.fileName = [dictionary objectForKey:#"fileName"];
tmp.photographer = [dictionary objectForKey:#"photographer"];
tmp.title = [dictionary objectForKey:#"title"];
tmp.license = [dictionary objectForKey:#"license"];
return tmp;
}
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
}
#end
I then set up these objects in an array, like so:
NSString *path = [[NSBundle mainBundle] pathForResource:#"pictureLicenses" ofType:#"plist"];
NSArray *tmpDataSource = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *tmp = [[NSMutableArray alloc] init];
self.dataSource = tmp;
[tmp release];
for (NSDictionary *dict in tmpDataSource) {
pictureData *pic = [pictureData picDataWith:dict];
NSLog(#"%#", pic.title);
[self.dataSource addObject:pic];
}
Everything works smashingly. I have a table view which loads the proper picture images, and information, no problem. Upon running Instruments for leaks, I see that my pictureData object is leaks with every allocation.
I would assume that with having my object autoreleased I would not have to worry about manually allocating and deallocating them.
Perhaps is my issue that I use autorelease, which the autoReleasePool keeps a retain count of +1 and then when I add a pictureData object to my array, that also retains it? Thank you all for your time!
edit: Don't forget to call super! Thank you Sam!
Change dealloc to:
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
[super dealloc];
}
(call [super dealloc])
In your function, change the return value to include autorelease, like
+ (pictureData*)picDataWith:(NSDictionary *)dictionary
{
...
...
return [tmp autorelease];
}
When you add pictureData object to dataSource, you increase the retain count, so you should autorelease it while returning.
Hope it helps.
I have 3 classes
First -> MainViewController:
#interface MainViewController : UIViewController {
UtilityBadah *utility;
}
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
- (IBAction)option;
#end
#implementation MainViewController
#synthesize managedObjectContext = _managedObjectContext;
(IBAction)option{
UtilityBadah *util = [[UtilityBadah alloc] initWithContext:_managedObjectContext];
OptionController *ovc = [[OptionController alloc] init];
ovc.util = util;
ovc.managedObjectContext = _managedObjectContext;
[self.navigationController pushViewController:ovc animated:YES];
[util release];
[ovc release];
}
#end
Second -> UtilityBadah:
#interface UtilityBadah : NSObject {
NSManagedObjectContext *managedObjectContext;
NSString *kitab;
NSString *lagu;
NSString *font;
NSString *sizefont;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSString *kitab;
#property (nonatomic, retain) NSString *lagu;
#property (nonatomic, retain) NSString *font;
#property (nonatomic, retain) NSString *sizefont;
(id) initWithContext: (NSManagedObjectContext *) context;
#end
#implementation UtilityBadah
#synthesize managedObjectContext;
#synthesize kitab;
#synthesize lagu;
#synthesize font;
#synthesize sizefont;
-(id) initWithContext: (NSManagedObjectContext *) context {
NSError *err;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *enDesc = [NSEntityDescription entityForName:#"OptionDB" inManagedObjectContext:context];
[request setEntity:enDesc];
NSArray *arrData = [context executeFetchRequest:request error:&err];
for (OptionDB *data in arrData) {
lagu = data.lagu;
kitab = data.kitab;
font = data.font;
sizefont = data.sizefont;
}
return self;
}
Thrid -> OptionController:
#interface OptionController : UIViewController{
NSManagedObjectContext *managedObjectContext;
UtilityBadah *util;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) UtilityBadah *util;
#end
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
bla..bla..
NSLog(#"value is %#",self.util.kitab);
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
i wonder why this piece of code:
NSLog(#"value is %#",self.util.kitab);
cause an error "Receiced signa: "EXC_BAD_ACCESS" ?
i wonder ther somthing wrong the way i passed the UtilityBadah object from MainViewController to my OptionController.
Many thanks for any answer.
P.S what is wrong with my xcode 4.2 error information, why it always show "Program received signal: "EXC BAD ACCESS"? cant it be informative?
i think your init method is wrong, try assigning self to [super init] at the start, and doing all your set up after checking that self != nil. this is the basic form of an init:
- (id)init
{
self = [super init];
if (self)
//do setup
return self;
}
also, you are using a subclass of NSObject and associating a managed object context to it, you should look into core data in more detail, you should be using NSManagedObjects
The property name in the OptionController is util not utility
If you want to access the utility property in the UtilityBadah class you will have to do:
self.util.utility
In the UtilityBadah class, initWithContext method, change the for loop as following
for (OptionDB *data in arrData) {
self.lagu = data.lagu;
self.kitab = data.kitab;
self.font = data.font;
self.sizefont = data.sizefont;
}
In your case, the value is not retained since you have assigned without accessing through the property.
You need to allocate those objects first. Here's how your initWithContext method should look like:
-(id) initWithContext: (NSManagedObjectContext *) context {
self = [super init];
if (self) {
NSError *err;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *enDesc = [NSEntityDescription entityForName:#"OptionDB" inManagedObjectContext:context];
[request setEntity:enDesc];
NSArray *arrData = [context executeFetchRequest:request error:&err];
for (OptionDB *data in arrData) {
self.lagu = [NSString stringWithString:data.lagu];
self.kitab = [NSString stringWithString:data.kitab];
self.font = [NSString stringWithString:data.font];
self.sizefont = [NSString stringWithString:data.sizefont];
}
}
return self;
}
I do webservice requests with a UISegmentedControl, when I change segmentedItem and request fast the application crashes with this message:
[Session started at 2011-05-12
10:58:50 +0200.] Terminating in
response to SpringBoard's termination.
[Session started at 2011-05-12
11:06:31 +0200.] GNU gdb
6.3.50-20050815 (Apple version gdb-1516) (Fri Feb 11 06:19:43 UTC
2011) Copyright 2004 Free Software
Foundation, Inc. GDB is free software,
covered by the GNU General Public
License, and you are welcome to change
it and/or distribute copies of it
under certain conditions. Type "show
copying" to see the conditions. There
is absolutely no warranty for GDB.
Type "show warranty" for details. This
GDB was configured as
"--host=i386-apple-darwin
--target=arm-apple-darwin".tty /dev/ttys001 Loading program into
debugger… Program loaded. target
remote-mobile
/tmp/.XcodeGDBRemote-239-58 Switching
to remote-macosx protocol mem 0x1000
0x3fffffff cache mem 0x40000000
0xffffffff none mem 0x00000000 0x0fff
none run Running… [Switching to thread
11779] [Switching to thread 11779]
sharedlibrary apply-load-rules all
continue Program received signal:
“SIGKILL”. warning: Unable to read
symbols for
/Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.3
(8J2)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib
(file not found). kill quit
The Debugger has exited with status
0.(gdb)
Does anybody have an idea of how can I fix this?
Is this a problem because I'm not using NSOperationQueue?
And if so any suggestions how I can fix this would be very welcomed.
I can not find any memory leaks when running.
Next time I ran it this message got logged:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.3 (8J2)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
(gdb)
Here is the code for starting the connection:
Class header ServiceGetChildren:
#import <Foundation/Foundation.h>
#class Authentication;
#class AttendanceReportViewController;
#interface ServiceGetChildren : NSObject {
Authentication *authentication;
AttendanceReportViewController *attendanceReportViewController;
NSString *username;
NSString *password;
NSMutableString *authenticationString;
NSString *encodedLoginData;
NSMutableData *responseData;
NSMutableArray *childrensArray;
}
#property (nonatomic, retain) NSString *username;
#property (nonatomic, retain) NSString *password;
#property (nonatomic, retain) NSMutableString *authenticationString;
#property (nonatomic, retain) NSString *encodedLoginData;
#property (nonatomic, retain) NSMutableData *responseData;
#property (nonatomic, retain) NSMutableArray *childrensArray;
- (void)startService:(NSURL *)url :(NSString *)method withParent:(UIViewController *)controller;
#end
Class handling the request:
#import "ServiceGetChildren.h"
#import "JSON.h"
#import "Base64.h"
#import "AttendanceReportViewController.h"
#import "Authentication.h"
#implementation ServiceGetChildren
#synthesize appDelegate;
#synthesize username;
#synthesize password;
#synthesize authenticationString;
#synthesize encodedLoginData;
#synthesize responseData;
#synthesize childrensArray;
- (id) init {
if ((self = [super init])) {
}
return self;
}
- (void)startService:(NSURL *)url :(NSString *)method withParent:(UIViewController *)controller {
username = appDelegate.username;
password = appDelegate.password;
attendanceReportViewController = (AttendanceReportViewController *)controller;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[#"" stringByAppendingFormat:#"%#:%#", username, password];
encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
// Setup up the request with the url
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url
cachePolicy: NSURLRequestReloadIgnoringCacheData
timeoutInterval: 20.0];
[request setHTTPMethod:method];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
// Display the network indicator when the connection request started
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// Check that the NSURLConnection was successful and then initialize the responseData
if(connection) {
NSLog(#"Connection made");
responseData = [[NSMutableData data] retain];
}
else {
NSLog(#"Connection could not be made");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Connection finished loading.");
// Dismiss the network indicator when connection finished loading
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:#"Children"];
childrensArray = [NSMutableArray arrayWithArray:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadChildren];
[connection release];
[responseData release];
[jsonString release];
[parser release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection failure.");
NSLog(#"ERROR%#", error);
// Dismiss the network indicator when connection failure occurred
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection release];
// Inform the user that the server was unavailable
}
- (void) dealloc {
[attendanceReportViewController release];
[super dealloc];
}
Class header for AttendanceReportViewController:
#import <UIKit/UIKit.h>
#class ServiceGetGroups;
#class ServiceGetChildren;
#class DetailViewController;
#interface AttendanceReportViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
ServiceGetGroups *serviceGetGroups;
ServiceGetChildren *serviceGetChildren;
DetailViewController *detailViewController;
UISegmentedControl *segmentedControl;
IBOutlet UIToolbar *groupsToolbar;
NSMutableArray *btnArray;
NSInteger index;
IBOutlet UITableView *theTableView;
IBOutlet UILabel *attendanceLabel;
IBOutlet UILabel *abscentLabel;
IBOutlet UILabel *totalLabel;
NSMutableDictionary *selectRequestDictionary;
NSMutableDictionary *selectNameDictionary;
NSMutableArray *groupsArray;
NSMutableArray *childrensArray;
NSDictionary *childrensDictionary;
NSURL *url;
}
#property (nonatomic, retain) ServiceGetGroups *serviceGetGroups;
#property (nonatomic, retain) ServiceGetChildren *serviceGetChildren;
#property (nonatomic, retain) DetailViewController *detailViewController;
#property (nonatomic, retain) IBOutlet UIToolbar *groupsToolbar;
#property (nonatomic, retain) IBOutlet UITableView *theTableView;
#property (nonatomic, retain) IBOutlet UILabel *attendanceLabel;
#property (nonatomic, retain) IBOutlet UILabel *abscentLabel;
#property (nonatomic, retain) IBOutlet UILabel *totalLabel;
#property (nonatomic, retain) UISegmentedControl *segmentedControl;
#property (nonatomic) NSInteger index;
#property (nonatomic, retain) NSMutableArray *btnArray;
#property (nonatomic, retain) NSMutableDictionary *selectRequestDictionary;
#property (nonatomic, retain) NSMutableDictionary *selectNameDictionary;
#property (nonatomic, retain) NSMutableArray *groupsArray;
#property (nonatomic, retain) NSMutableArray *childrensArray;
#property (nonatomic, retain) NSDictionary *childrensDictionary;
#property (nonatomic, retain) NSURL *url;
- (void)setupSegmentedControl;
- (void)requestGroups;
- (void)requestChildren:(NSNumber *)groupId;
- (void)loadGroups;
- (void)loadChildren;
#end
Class that the Uses the UISegmentedControl:
#import "JSON.h"
#import "AttendanceReportViewController.h"
#import "CustomCellViewController.h"
#import "DetailViewController.h"
#import "ServiceGetGroups.h"
#import "ServiceGetChildren.h"
#import "Group.h"
#import "Child.h"
#implementation AttendanceReportViewController
#synthesize serviceGetGroups;
#synthesize serviceGetChildren;
#synthesize detailViewController;
#synthesize segmentedControl;
#synthesize groupsToolbar;
#synthesize index;
#synthesize btnArray;
#synthesize theTableView;
#synthesize attendanceLabel;
#synthesize abscentLabel;
#synthesize totalLabel;
#synthesize selectRequestDictionary;
#synthesize selectNameDictionary;
#synthesize groupsArray;
#synthesize childrensArray;
#synthesize childrensDictionary;
#synthesize url;
#pragma mark -
#pragma mark View lifecycle
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
- (void)requestGroups {
NSURL *groupsURL = [NSURL URLWithString:#"http://services/groups"];
[serviceGetGroups startService:groupsURL :#"GET" withParent:self];
}
- (void)requestChildren:(NSNumber *)groupId {
NSLog(#"%#", groupId);
NSString *baseURL = #"http://services/group/";
NSString *method = [NSString stringWithFormat:#"%#%#", groupId, #"/children"];
NSString *theURL = [NSString stringWithFormat:#"%#%#", baseURL, method];
self.url = [NSURL URLWithString:theURL];
NSLog(#"%#", self.url);
[serviceGetChildren startService:self.url :#"GET" withParent:self];
}
- (void)loadGroups {
// Retrieve a array with dictionaries of groups from ServiceGetGroups
self.groupsArray = [[serviceGetGroups.groupsArray copy] autorelease];
// The array to hold segmentedItems for the segmentedControl, representing groups buttons
btnArray = [NSMutableArray arrayWithObjects: #"Alla", nil];
for (NSDictionary *groupDict in groupsArray) {
// Add each groups name to the btnArray as segmentedItems for the segmentedControl
[btnArray addObject:[groupDict objectForKey:#"Name"]];
}
// Create a new NSMutableDictionary with group names as keys and group id´s as values
// used for reference to segementedControl items to make request to serviceGetChildren
self.selectRequestDictionary = [NSMutableDictionary dictionary];
for (NSDictionary *dict in groupsArray) {
[selectRequestDictionary setObject:[dict objectForKey:#"Id"] forKey:[dict objectForKey:#"Name"]];
}
// Create a new NSMutableDictionary with group id´s as keys and group names as values
// used for retrieving a groupName from a passed id
self.selectNameDictionary = [NSMutableDictionary dictionary];
for (NSDictionary *dict in groupsArray) {
[selectNameDictionary setObject:[dict objectForKey:#"Name"] forKey:[dict objectForKey:#"Id"]];
}
[self setupSegmentedControl];
}
- (void)setupSegmentedControl {
// Setup the UISegmentedControl as groups buttons
segmentedControl = nil;
segmentedControl = [[UISegmentedControl alloc] initWithItems:btnArray];
segmentedControl.tintColor = [UIColor darkGrayColor];
segmentedControl.selectedSegmentIndex = 0;
segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.frame = CGRectMake(0, 0, 300, 30);
// Setup the target and actions for the segmentedControl
[segmentedControl addTarget:self
action:#selector(selectGroup:)
forControlEvents:UIControlEventValueChanged];
// Add the UISegmentedControl as a UIBarButtonItem subview to the UIToolbar
UIBarButtonItem *segmentedItem = [[[UIBarButtonItem alloc] initWithCustomView:segmentedControl] autorelease];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
NSArray *groupsButtons = [NSArray arrayWithObjects:flexSpace, segmentedItem, flexSpace, nil];
[groupsToolbar setItems:groupsButtons];
[flexSpace release];
}
- (void)loadChildren {
// Retrieve a array with dictionaries of children from ServiceGetChildren
self.childrensArray = [[serviceGetChildren.childrensArray copy] autorelease];
// TODO create seperate method - Setup compilation bar values
int total = [childrensArray count];
totalLabel.text = [NSString stringWithFormat:#"%d", total];
[theTableView reloadData];
}
// Handles UIControlEventValueChanged for UISegmentedControl, retreives the name and id for a selected group
- (void)selectGroup:(UISegmentedControl *)theSegmentedControl {
NSString *selectedGroup = [segmentedControl titleForSegmentAtIndex: [segmentedControl selectedSegmentIndex]];
NSNumber *selectedId = [selectRequestDictionary objectForKey:selectedGroup];
// Persist the selectedSegmentIndex when view switches to detaildView
index = [segmentedControl selectedSegmentIndex];
// Request children based on the selected groupId
[self requestChildren:selectedId];
}
- (void)viewDidLoad {
[self requestGroups];
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
//self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [childrensArray count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
// Load from nib
CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:#"CustomCellView"
owner:nil
options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[UITableViewCell class]]) {
cell = (CustomCellViewController *) currentObject;
break;
}
}
}
// Set up a children dictionary for easy retrieving specific values to display in the UITableView
childrensDictionary = [childrensArray objectAtIndex:indexPath.row];
NSNumber *idForName = [childrensDictionary valueForKey:#"GroupId"];
NSString *name = [NSString stringWithFormat:#"%# %#",
[childrensDictionary valueForKey:#"Firstname"],
[childrensDictionary valueForKey:#"Surname"]];
NSString *group = [NSString stringWithFormat:#"%#",
[selectNameDictionary objectForKey:idForName]];
cell.childNameLabel.text = name;
cell.groupNameLabel.text = group;
cell.scheduleLabel.text = #"Schema";
cell.deviationLabel.text = #"Avvikelse";
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push the detailedViewController.
if (detailViewController == nil) {
DetailViewController *_detailViewcontroller = [[DetailViewController alloc]
initWithNibName:#"DetailView" bundle:nil];
self.detailViewController = _detailViewcontroller;
[_detailViewcontroller release];
}
childrensDictionary = [childrensArray objectAtIndex:indexPath.row];
NSNumber *idForName = [childrensDictionary valueForKey:#"GroupId"];
NSString *group = [NSString stringWithFormat:#"%#",
[selectNameDictionary objectForKey:idForName]];
[self.detailViewController initWithDetailsSelected:childrensDictionary:group];
[self.navigationController pushViewController:detailViewController animated:YES];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
segmentedControl = nil;
}
- (void)dealloc {
[segmentedControl release];
[groupsArray release];
[childrensArray release];
[detailViewController release];
[super dealloc];
}
#end
OK here we go. First of all, I could not test the code, so I need your feedback.
The main problem with this class is, you only have one instance, which you reuse every time you hit the segmented control. This leads to creation of new instances of the NSURLConnection. So let's correct a bit in the header. I changed the NSString properties to copy. Have a look at this Q&A to know why, however this is not important for the improvement, just wanted to let you know.
I've removed Authentication *authentication; looked like you don't use it.
Added NSURLConnection as property so we keep a reference on it.
Header file
#class Authentication;
#class AttendanceReportViewController;
#interface ServiceGetChildren : NSObject {
AttendanceReportViewController *attendanceReportViewController;
NSString *username;
NSString *password;
NSMutableString *authenticationString;
NSString *encodedLoginData;
NSMutableData *responseData;
NSMutableArray *childrensArray;
NSURLConnection *connection;
}
#property (nonatomic, copy) NSString *username;
#property (nonatomic, copy) NSString *password;
#property (nonatomic, retain) NSMutableString *authenticationString;
#property (nonatomic, copy) NSString *encodedLoginData;
#property (nonatomic, retain) NSMutableData *responseData;
#property (nonatomic, retain) NSMutableArray *childrensArray;
#property (nonatomic, retain) NSURLConnection *connection
- (void)startService:(NSURL *)url :(NSString *)method withParent:(UIViewController *)controller;
#end
Next comes the Implementation file. I only altered the startService method and dealloc.
If you declare properties, use them :) Have a look at this Q&A for some explanations on synthesized properties.
Always release what you own, so I added release code in the dealloc.
Cancel the previous request!!! If there is none, the message is sent to nil, which causes no harm.
Implementation file
- (void)startService:(NSURL *)url:(NSString *)method withParent:(UIViewController *)controller
{
self.username = appDelegate.username;
self.password = appDelegate.password;
[connection cancel];
attendanceReportViewController = (AttendanceReportViewController *)controller;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString *)[#"" stringByAppendingFormat:#"%#:%#", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
// Setup up the request with the url
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:20.0];
[request setHTTPMethod:method];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
self.connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
// Display the network indicator when the connection request started
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// Check that the NSURLConnection was successful and then initialize the responseData
if (connection) {
NSLog(#"Connection made");
self.responseData = [NSMutableData data];
} else {
NSLog(#"Connection could not be made");
}
}
...
- (void) dealloc
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection cancel];
[connection release];
[appDelegate release];
[responseData release];
[username release];
[password release];
[authenticationString release];
[encodedLoginData release];
[responseData release];
[childrensArray release];
[super dealloc];
}
Hope this helps for the next steps. However I think we will have to work a bit on the solution until it's final.