unrecognized selector sent to instance... Source code link inside - iphone

I'm going crazy with this my little app... Please help me!!!
this is the source code of the app: Smoking.zip
It only saves a .dat file with an NSMutableArray.
Now, the first time you will launch the app, try to click the cigarette button sometimes: Everything should working fine.
Ok, now close the app, re-open it, and click again on the button. This time the app will crash with the "unrecognized selector sent to instance 0x5d18d60" error.
I was sure the problem was in saving the data, because when i commented the line "[theData writeToFile:dataFilePath atomically:YES];" in the "saveData" method the error disappeared.
Later i discovered that it appears again if i try to read the data from the NSMutableArray.
Please take a moment to check my project and help me, beacause i'm going crazy about that!!
Here's some code:
#import "SmokingAppDelegate.h"
#import "SmokingViewController.h"
#import "Cig.h"
#implementation SmokingAppDelegate
#synthesize window;
#synthesize viewController, dataFilePath, smokeArray;
#pragma mark -
#pragma mark Application lifecycle
- (id) init {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"a.dat"];
[self setDataFilePath:path];
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:dataFilePath]
) {
//open it and read it
NSLog(#"data file found. reading into memory");
smokeArray = [[NSMutableArray alloc] init];
NSMutableData *theData;
NSKeyedUnarchiver *decoder;
NSMutableArray *tempArray;
theData = [NSData dataWithContentsOfFile:dataFilePath];
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
tempArray = [decoder decodeObjectForKey:#"smokeArray"];
[self setSmokeArray:tempArray];
[decoder finishDecoding];
[decoder release];
} else {
NSLog(#"no file found. creating empty array");
smokeArray = [[NSMutableArray alloc] init];
[smokeArray insertObject:[[NSNumber alloc] initWithInt:0] atIndex:0];
}
// [self logArrayContents];
return self;
}
- (void) logArrayContents {
for(int j = 1; j < [smokeArray count]; j++) {
int f = [[[smokeArray objectAtIndex:j] num] intValue];
NSLog(#"%i. - %d", j, f);
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
-(void) saveData {
NSMutableData *theData;
NSKeyedArchiver *encoder;
theData = [NSMutableData data];
encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
[encoder encodeObject:smokeArray forKey:#"smokeArray"];
[encoder finishEncoding];
[theData writeToFile:dataFilePath atomically:YES];
[encoder release];
NSLog(#"Saved");
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[viewController release];
[window release];
[dataFilePath release];
[smokeArray release];
[super dealloc];
}
#end
#import "SmokingViewController.h"
#import "SmokingAppDelegate.h"
#import "Cig.h"
#implementation SmokingViewController
#synthesize label;
- (void)viewDidLoad {
[super viewDidLoad];
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
//controlla se il giorno รจ lo stesso rispetto a quello dell'ultima sigaretta fumata
if ([mainDelegate.smokeArray count] > 1) {
Cig *oldCig = [mainDelegate.smokeArray lastObject];
NSArray *tempArray = [self quando];
if ( [[tempArray objectAtIndex:0] intValue]==[[oldCig.dat objectAtIndex:0] intValue]
&& [[tempArray objectAtIndex:1] intValue]==[[oldCig.dat objectAtIndex:1] intValue]
&& [[tempArray objectAtIndex:2] intValue]==[[oldCig.dat objectAtIndex:2] intValue]
) {
N = [oldCig.num intValue];
}
else {
N = 0;
}
[oldCig release];
[tempArray release];
}
//scrive quante sigarette si sono fumate oggi
label.text = [NSString stringWithFormat: #"Today you smoked %d cigarettes",N];
}
- (IBAction) smoke:(UIButton * ) button {
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"L'array contiene %d sigarette", [mainDelegate.smokeArray count]-1);
N += 1;
[self addNewCigToArray];
[mainDelegate logArrayContents];
[mainDelegate saveData];
label.text = [NSString stringWithFormat: #"Today you smoked %d cigarettes",N];
}
- (void) addNewCigToArray {
//NSLog(#"new cigarette smoked");
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
Cig *newCig = [[Cig alloc] init];
[newCig setDat:[self quando]];
[newCig setNum:[[NSNumber alloc] initWithInt:N]];
[mainDelegate.smokeArray addObject:newCig];
[newCig release];
//[mainDelegate logArrayContents];
}
- (NSArray *) quando {
NSDateFormatter *timeFormat = [[NSDateFormatter alloc] init];
// 0 - Year
[timeFormat setDateFormat:#"YYYY"];
NSString *year = [timeFormat stringFromDate:[NSDate date]];
// 1 - Month
[timeFormat setDateFormat:#"MM"];
NSString *month = [timeFormat stringFromDate:[NSDate date]];
// 2 - Day
[timeFormat setDateFormat:#"dd"];
NSString *day = [timeFormat stringFromDate:[NSDate date]];
// 3 - Hour
[timeFormat setDateFormat:#"HH"];
NSString *hour = [timeFormat stringFromDate:[NSDate date]];
// 4 - Minute
[timeFormat setDateFormat:#"mm"];
NSString *min = [timeFormat stringFromDate:[NSDate date]];
// 5 - Second
[timeFormat setDateFormat:#"ss"];
NSString *sec = [timeFormat stringFromDate:[NSDate date]];
NSArray *newArray = [[NSArray alloc] initWithObjects:year,month,day,hour,min,sec,nil];
return newArray;
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end

Okay, I am an iPhone newbie so take my suggestion in stride. You could try creating an NSData object, initializing it with theData, and then calling writeToFile on the new NSData object instead of the NSMutableData object.

Related

Memory Leak while using NSDateFormatter

I have seen many questions/answers on memory leaks in NSDateFormatter, but none seems to help me determine what is causing memory to leak in my app. Here is my code:
- (id)init
{
if ((self = [super init]))
{
items = [[NSMutableArray alloc] init];
events = [[NSMutableArray alloc] init];
buffer = [[NSMutableData alloc] init];
format = [[NSDateFormatter alloc] init];
lastFromDate = #"";
}
return self;
}
- (void)presentingDatesFrom:(NSDate *)fromDate to:(NSDate *)toDate delegate:(id<KalDataSourceCallbacks>)delegate
{
[format setTimeZone:[NSTimeZone systemTimeZone]];
[format setDateFormat:#"MM/dd/yyyy"];
NSString *stringFromDate = [NSString stringWithString:[format stringFromDate:fromDate]];
NSString *stringToDate = [NSString stringWithString:[format stringFromDate:toDate]];
NSLog(#"From date: %#, To date: %#", stringFromDate, stringToDate);
[self didDatesChange:stringFromDate];
if (dataReady) {
[callback loadedDataSource:self];
return;
}
callback = delegate;
[self retrieveEventData:stringFromDate to:stringToDate];
}
- (void)dealloc
{
[items release];
[events release];
[buffer release];
[lastFromDate release];
[format release];
[super dealloc];
}
When I run "Profile" -> "Leaks", I get a memory leak every time the function is called on line
NSString *stringFromDate = [NSString stringWithString:[format stringFromDate:fromDate]];
Can someone explain what might be going on?
thanks, mike
FYI you can change this:
NSString *stringFromDate = [NSString stringWithString:[format stringFromDate:fromDate]];
to this:
NSString *stringFromDate = [format stringFromDate:fromDate];
stringWithString should return an autoreleased NSString though so I don't believe that is the source of your leak. It looks like there is no leak in your code to me.
you just use bellow method for get string from date its work properly......
-(NSString *)StringFromDate:(NSDate *)DateLocal{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM/dd/yyyy"];
NSString *dateString = [dateFormat stringFromDate:DateLocal];
NSLog(#"Date is HERE =====>> %#",dateString);
return dateString;
}
after when you want to get date string just use like bellow....
NSString *stringFromDate = [self stringFromDate:fromDate]];
[stringfromdate retain];
NSString *stringToDate = [self stringFromDate:toDate]];
[stringTodate retain];
and above -(NSString *)StringFromDate:(NSDate *)DateLocal method is must be define in your viewcontroller.m file....
Its work fine....

My app crashes with "Program received EXC_BAD_ACCESS" error iphone

When my app launches from BACKGROUND , I am running a new thread to get AddresssBook data using notification center. Here is my code which shows how I call the method
-(void)appLaunchedFromBackground:(NSNotification *) notification {
// NSThread *backgroundThread; is my ivar
backgroundThread = [[NSThread alloc]initWithTarget:self selector:#selector(getUpdatedAddressBookData) object:nil];
[backgroundThread start];
}
-(void)getUpdatedAddressBookData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AddressBook *addBook = [[AddressBook alloc]init];
[addBook fetchAddressBookDataInBackground];
[addBook release];
[pool drain];
}
Here is my code for fetchAddressBookDataInBackground method
-(void)fetchAddressBookDataInBackground {
if (self.tempArray == nil) {
NSMutableArray *temp = [[NSMutableArray alloc]init];
self.tempArray = temp;
[temp release];
}
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *tempPeople = [[NSArray alloc]init];
tempPeople = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
APP_DELGATE.people = [NSArray arrayWithArray:tempPeople];
int peoCount = [APP_DELGATE.people count];
for (int i=0; i<peoCount; i++) {
ABRecordRef record = [APP_DELGATE.people objectAtIndex:i];
NSNumber *recordId = [NSNumber numberWithInteger:ABRecordGetRecordID(record)];
// Get fname, lname, company
NSString *fnm = (NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty) ;
NSString *lnm = (NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty) ;
NSString *comp = (NSString*)ABRecordCopyValue(record,kABPersonOrganizationProperty);
// Get Ph no
ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(record, kABPersonPhoneProperty);
NSArray *tempPhNos = (NSArray*)ABMultiValueCopyArrayOfAllValues(phoneNumberProperty);
NSArray* phoneNumbers = [self getPhoneNoWithoutSymbols:tempPhNos];
NSString *strPhoneNos = [self getStringRepresentaionFromArray:phoneNumbers];
// Get emails
ABMultiValueRef emailProperty = ABRecordCopyValue(record, kABPersonEmailProperty);
NSArray* emails = (NSArray*)ABMultiValueCopyArrayOfAllValues(emailProperty);
NSString *strEmails = [self getStringRepresentaionFromArray:emails];
// Get URL
ABMultiValueRef urlProperty = ABRecordCopyValue(record, kABPersonURLProperty);
NSArray* urls = (NSArray*)ABMultiValueCopyArrayOfAllValues(urlProperty);
NSString *strURLs = [self getStringRepresentaionFromArray:urls];
// Get Address
ABMultiValueRef address=ABRecordCopyValue(record, kABPersonAddressProperty);
CFDictionaryRef dic=nil;
NSMutableArray *addressArray = [[NSMutableArray alloc]init];
for (int index=0; index<ABMultiValueGetCount(address); index++) {
dic=ABMultiValueCopyValueAtIndex(address, index);
NSString* labelName=(NSString*)ABMultiValueCopyLabelAtIndex(address, index);
if (labelName) {
NSString *street =(NSString*) CFDictionaryGetValue(dic, kABPersonAddressStreetKey);
NSString *city= (NSString*)CFDictionaryGetValue(dic, kABPersonAddressCityKey) ;
NSString *state= CFDictionaryGetValue(dic, kABPersonAddressStateKey);
NSString *country=CFDictionaryGetValue(dic, kABPersonAddressCountryKey);
NSString *zipcode=CFDictionaryGetValue(dic, kABPersonAddressZIPKey);
NSString *addressDetails=#"";
if (street) {
addressDetails=[NSString stringWithFormat:#"%# ",street];
}
if (city) {
addressDetails=[NSString stringWithFormat:#"%# %# ",addressDetails,city];
}
if (state) {
addressDetails=[NSString stringWithFormat:#"%# %# ",addressDetails,state];
}
if (country) {
addressDetails=[NSString stringWithFormat:#"%# %# ",addressDetails,country];
}
if (zipcode) {
addressDetails=[NSString stringWithFormat:#"%# %# ",addressDetails,zipcode];
}
[addressArray addObject:addressDetails];
}
[labelName release];
CFRelease(dic);
}
NSString *strAddress = [self getStringRepresentaionFromArray:addressArray];
// Get Notes
NSString *noteString=(NSString *)ABRecordCopyValue(record, kABPersonNoteProperty);
// Get Birthdate
NSDate *birthDate=(NSDate*)ABRecordCopyValue(record, kABPersonBirthdayProperty) ;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMMM dd yyyy"];
NSString *birthdateString = [formatter stringFromDate:birthDate];
[formatter release];
// Get user image
UIImage *image = nil;
if( ABPersonHasImageData( record ) ) {
NSData *imageData = (NSData*)ABPersonCopyImageData(record);
image = [UIImage imageWithData:imageData];
[imageData release];
}
NSString *fullName = [NSString stringWithFormat:#"%# %#",fnm,lnm];
// Create User object & add it to array
User *user = [[User alloc]initUserWithUniqID:recordId.intValue FirstName:fnm lastName:lnm compositeName:fullName company:comp phoneNumbers:strPhoneNos emails:strEmails urls:strURLs address:strAddress notes:noteString dob:birthdateString userImage:image];
[self.tempArray addObject:user];
CFRelease(phoneNumberProperty);
[tempPhNos release];
CFRelease(emailProperty);
[emails release];
CFRelease(urlProperty);
[urls release];
CFRelease(address);
[addressArray release];
[birthDate release];
[comp release];
[noteString release];
[lnm release];
[fnm release];
[user release];
}
[tempPeople release];
CFRelease(addressBook);
addressBook = nil;
self.tempArray = [NSMutableArray arrayWithArray:[self.tempArray sortedArrayUsingSelector:#selector(compare:)]];
APP_DELGATE.allUsersArray = self.tempArray;
NSDictionary *dic = [NSDictionary dictionaryWithObject:self.tempArray forKey:BATCH_DONE_KEY];
[[NSNotificationCenter defaultCenter] postNotificationName:BACKGROUND_WORK_DONE_NOTIFICATION object:self userInfo:dic];
}
-(NSMutableArray*)getPhoneNoWithoutSymbols:(NSArray*)array {
if (self.phNoArray == nil) {
NSMutableArray *temp = [[NSMutableArray alloc]init];
self.phNoArray = temp;
[temp release];
}
[self.phNoArray removeAllObjects];
for (NSString *str in array) {
[self.phNoArray addObject:[self getPhNo:str]];
}
return self.phNoArray;
}
-(NSString*)getPhNo:(NSString*)str {
NSString *str0 = [str stringByReplacingOccurrencesOfString:#" " withString:#""];
NSString *str1 = [str0 stringByReplacingOccurrencesOfString:#"(" withString:#""];
NSString *str2 = [str1 stringByReplacingOccurrencesOfString:#")" withString:#""];
NSString *str3 = [str2 stringByReplacingOccurrencesOfString:#"-" withString:#""];
return str3;
}
-(NSString*)getStringRepresentaionFromArray:(NSArray*)array {
return [array componentsJoinedByString:DELIMITER_SYMBOL];
}
But my app crashes with "Program received EXC_BAD_ACCESS" error at any line where I am using "ABRecordCopyValue" function . What I am missing? I am not getting whats wrong in my code?
I tried setting NSZombieEnabled = YES , but its not showing any message. Just saying "Program received EXC_BAD_ACCESS" at any line using ABRecordCopyValue function & in console I see (gdb) thats it.
Any knid of help is highly appreciated. Thanks.

Memory management advice - how to handle Zombies?

In the below sample code, I am a bit lost as to why I am getting a NZombie on the line:
[Category getInitialDataToDisplay:[self getDBPath]];
I have looked through SO posts and other documentation but am new to objective-c and am spinning my wheels on this.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//Copy database to the user's phone if needed.
[self copyDatabaseIfNeeded];
// Init the Array
activeCategories = [[NSMutableArray alloc] init];
activeSubjects = [[NSMutableArray alloc] init];
categories = [[NSMutableArray alloc] init];
subjects = [[NSMutableArray alloc] init];
quotes = [[NSMutableArray alloc] init];
quoteMaps = [[NSMutableArray alloc] init];
//Initialize the Category array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.categories = tempArray;
[tempArray release];
//Once the db is copied, get the initial data to display on the screen.
[Category getInitialDataToDisplay:[self getDBPath]];
//populate active subjects and categories:
activeCategories = [self getActiveCategories];
activeSubjects = [self getActiveSubjects];
// sort data
NSSortDescriptor *categorySorter;
NSSortDescriptor *subjectSorter;
categorySorter = [[NSSortDescriptor alloc]initWithKey:#"category_title" ascending:YES];
subjectSorter = [[NSSortDescriptor alloc]initWithKey:#"title" ascending:YES];
NSArray *sortDescriptorsCat = [NSArray arrayWithObject:categorySorter];
NSArray *sortDescriptorsSub = [NSArray arrayWithObject:subjectSorter];
[self.categories sortUsingDescriptors:sortDescriptorsCat];
[self.subjects sortUsingDescriptors:sortDescriptorsSub];
[categorySorter release];
[subjectSorter release];
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
...
- (void)dealloc {
[activeSubjects release];
[activeCategories release];
[categories autorelease];
[subjects autorelease];
[quotes autorelease];
[quoteMaps autorelease];
[navigationController release];
[window release];
[super dealloc];
}
Here is the getInitialDataToDisplay:
+ (void) getInitialDataToDisplay:(NSString *)dbPath {
// Use this section to bring in database and populate the array
FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
[database open];
QuotesAppDelegate *appDelegate = (QuotesAppDelegate *)[[UIApplication sharedApplication] delegate];
//appDelegate.categories = [appDelegate.categories sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
//POPULATE THE SUBJECT
FMResultSet *result_subjects = [database executeQuery:#"select * from SUBJECT"];
while([result_subjects next]) {
NSInteger primaryKey = [result_subjects intForColumn:#"SUBJECT_ID"];
Subject *sub = [[Subject alloc] initWithPrimaryKey:primaryKey];
sub.title = [result_subjects stringForColumn:#"SUBJECT"];
sub.category_title = [result_subjects stringForColumn:#"CATEGORY"];
sub.active = [result_subjects intForColumn:#"ACTIVE"];
sub.isDirty = NO;
[appDelegate.subjects addObject:sub];
[sub release];
}
FMResultSet *result_categories = [database executeQuery:#"select distinct category from SUBJECT"];
while([result_categories next]) {
Category *cat = [[Category alloc] init];
cat.category_title = [result_categories stringForColumn:#"CATEGORY"];
NSLog(#"loading category: %#", cat.category_title);
QuotesAppDelegate *appDelegate = (QuotesAppDelegate *)[[UIApplication sharedApplication] delegate];
for (Subject *sb in appDelegate.subjects){
if([cat.category_title isEqualToString:sb.category_title]){
[cat.subjects addObject:sb];
NSLog(#" Adding subject: %# cat.subjects.count=%i", sb.title, cat.subjects.count);
}
}
[appDelegate.categories addObject:cat];
[cat release];
}
//POPULATE THE QUOTES
FMResultSet *result_quotes = [database executeQuery:#"select * from QUOTE"];
while([result_quotes next]) {
Quote *sub = [Quote alloc];
sub.quote_id = [result_quotes stringForColumn:#"QUOTE_ID"];
sub.quote_date = [result_quotes stringForColumn:#"DATE"];
sub.title = [result_quotes stringForColumn:#"DESC1"];
sub.desc2 = [result_quotes stringForColumn:#"DESC2"];
sub.excerpt = [result_quotes stringForColumn:#"EXCERPT"];
sub.note = [result_quotes stringForColumn:#"NOTES"];
sub.isDirty = NO;
[appDelegate.quotes addObject:sub];
[sub release];
}
//POPULATE THE QUOTE_MAPS
FMResultSet *result_quote_map = [database executeQuery:#"select * from QUOTE_MAP"];
while([result_quote_map next]) {
QuoteMap *sub = [QuoteMap alloc];
sub.quote_id = [result_quote_map stringForColumn:#"QUOTE_ID"];
sub.quote_map_id = [result_quote_map stringForColumn:#"QUOTE_MAP_ID"];
sub.subject_id = [result_quote_map stringForColumn:#"SUBJECT_ID"];
sub.isDirty = NO;
[appDelegate.quoteMaps addObject:sub];
[sub release];
}
[database close];
NSLog(#"Count of categories: %i", appDelegate.categories.count);
NSLog(#"Count of subjects: %i", appDelegate.subjects.count);
NSLog(#"Count of quotes: %i", appDelegate.quotes.count);
NSLog(#"Count of quoteMaps: %i", appDelegate.quoteMaps.count);
}
Here is the getDbPath:
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"reference.db"];
}
Sometimes, the best thing to do is build->analyze ( cmd shift b ). This will point out your bug right away in almost all cases.
Best of luck!
categories = [[NSMutableArray alloc] init];
.
.
//Initialize the Category array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.categories = tempArray;
[tempArray release];
u've setup categories, then setup the tempArray, replaced the one in categories with it thus making a leak, then released the temp arrayObject, which what categories is now also pointing on, so unless "self.categories" is a retained property it will be a zombie. there seems to be something wrong there.
I may need to see some more of your code (the property declarations and their synthesis to make sure.
is the Zombie called on "getInitialDataToDisplay" or on "getDBPath"
try dividing it on 2 lines to know pin point more
I think you have not declare Category as retained property in .h file.If not, add following line in your .h file
#property (nonatomic, retain) NSArray Category;
And synthesize the property in .m as-
#synthesize Category;
I think it will help ....

Cannot figure out why my app crashes when I use NSKeyedArchivers / NSKeyedUnarchivers

I am developing my first iphone 'Diary' app, which uses custom 'Entry' objects that hold an NSString title, NSString text and NSDate creationDate. When I try to archive an NSMutableArray of Entry objects, and later retrieve them the next time the view loads, the app crashes. I have gone through a bunch of sample codes and examples that use NSKeyedArchivers, but still couldn't figure out why that happens. I am guessing there is a problem with the initialization of the array that holds the entries but not sure...
Here is the code, maybe you could find something that I have persistently overseen..."
//--------- Entry.m---------------
- (id) initWithCoder:(NSCoder *)aDecoder{
if ((self = [super init])) {
self.title = [[aDecoder decodeObjectForKey:#"title"] retain];
self.text = [[aDecoder decodeObjectForKey:#"text"] retain];
self.created = [[aDecoder decodeObjectForKey:#"created"] retain];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.title forKey:#"title"];
[aCoder encodeObject:self.text forKey:#"text"];
[aCoder encodeObject:self.created forKey:#"created"];
}
//-------------- Diary View Controller.m
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
- (void) writeDataToArchive {
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[archiver encodeObject:self.entriesArray forKey:#"entriesArray"];
[archiver finishEncoding];
BOOL result = [data writeToFile:[self dataFilePath] atomically:YES];
[archiver release];
[data release];
}
- (void)addItem:sender {
int count = [entriesArray count] +1;
NSString *newEntryTitle = [NSString stringWithFormat:#"Entry %d", count];
Entry *anEntry = [[Entry alloc] initWithTitle:newEntryTitle text:#"-"
created:[NSDate date]];
[entriesArray addObject:anEntry];
[self.tableView reloadData];
[anEntry release];
[self writeDataToArchive];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSData *data = [[NSMutableData alloc]
initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
initForReadingWithData:data];
NSMutableArray *array = [unarchiver decodeObjectForKey:#"entriesArray"];
entriesArray = [array mutableCopy];
[array release];
[unarchiver finishDecoding];
[unarchiver release];
[data release];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
// ... some other stuff
NSUInteger row = indexPath.row;
Entry *entry = [entriesArray objectAtIndex:row];
cell.textLabel.text = entry.title;
return cell;
}
Thanks a lot.
When you read an array back out with NSKeyedUnarchivers you always get an unmutable copy back. You would need to declare *array as NSArray or just get rid of array all together.
entriesArray = [[unarchiver decodeObjectForKey:#"entriesArray"] mutableCopy];
And #JeremyP points out another issue. Since you didn't alloc or retain *array you should not release it.
You should not release array in viewDidLoad because you do not own it.
Please review the Cocoa memory management Rules because there are a couple of other memory management issues in your code. In particular,
self.title = [[aDecoder decodeObjectForKey:#"title"] retain];
self.text = [[aDecoder decodeObjectForKey:#"text"] retain];
self.created = [[aDecoder decodeObjectForKey:#"created"] retain];
in your initWithCoder: method all leak on the assumption the properties are retain or copy.

giving nil while accessing the nsmutable array

i am parsing a json object and storing the song objects in songs, a nsmutable array.
while am displaying the image of the song i.e. while accessing the object from the array its giving all values nil in that object.
in the following code in setSongsScrollView method, in for loop while accessing the song object from songs array its showing nill in the debugger and crashing with error EXEBadacess.But the count of that array is giving correct.
can any body help me out please
- (void)viewWillAppear:(BOOL)animated{
[super viewDidLoad];
[self parsingTheStation];
[self load_images];
[self setSongsScrollView];
}
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
- (void)parsingTheStation{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http:...."]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *jsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:nil];
songs =[[NSMutableArray alloc]init];
NSArray *songObjects = [dictionary objectForKey:#"songs"];
for(NSDictionary *s in songObjects){
aSong = [[Song alloc] init];
aSong.artist = [s objectForKey:#"by"];
aSong.genre = [s objectForKey:#"genre"];
aSong.cover = [s objectForKey:#"cover"];
aSong.song_id = [s objectForKey:#"id"];
aSong.rank = [s objectForKey:#"rank"];
aSong.title = [s objectForKey:#"title"];
aSong.link = [s objectForKey:#"link"];
[songs addObject:aSong];
[aSong release];
}
NSLog(#"total number of songs is : %d",[songs count]);
}
-(void)setSongsScrollView {
songsContainer = [[UIScrollView alloc]init];
int songsCount = [self.songs count];
//totla no. of songs we get +4
int tSongs = songsCount+4;
int n = sqrt(tSongs);
int p = n,q = n;
int remSongs = tSongs-(n*n);
if(remSongs >= n){
q = q+(remSongs/n);
if((remSongs%n)>0)
q++;
}else q++;
for(int i=0;q>p;i++){
q--;
p++;
}
NSLog(#"total songs..%d",tSongs);
NSLog(#"total rows..%d",q);
NSLog(#"total columns..%d",p);
songsContainer.contentSize = CGSizeMake(120*q, 120*p);
int x =0, y=240, col=1;
for(int i=0;i<songsCount;i++){
CGRect imgFrame = CGRectMake(x, y, 118, 118);
NSLog(#"songs conunt ...%d",[songs count]);
Song *thesong = [[Song alloc]init];
thesong = [self.songs objectAtIndex:i];
NSString *filename = [NSString stringWithFormat:#"%#/%#", [LazyImageView dataPath], [thesong.cover lastPathComponent]];
UIImageView *tempImg = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filename]];
tempImg.tag = i;
tempImg.frame = imgFrame;
[songsContainer addSubview:tempImg];
[tempImg release];
[thesong release];
y += 120;
if(y>=(120*p)){
NSLog(#"total y..%d",y);
col++;
x += 120;
if(col>=3)
y=0;
else
y=240;
}
}
NSLog(#"total y..%d",y);
NSLog(#"content size..%d,%d",120*q,120*p);
}
-(void)load_images{
for(int i=0;i<[songs count];i++){
Song *rsong = [[Song alloc]init];
rsong = [self.songs objectAtIndex:i];
lazyBigImg = [[LazyImageView alloc] init];
NSURL* url = [NSURL URLWithString:rsong.cover];
[lazyBigImg loadImageFromURL:url];
[lazyBigImg release];
[rsong release];
}
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[songs release];
[lazyBigImg release];
[onAirBtn release];
[chartsBtn release];
[dealsBtn release];
[searchBtn release];
[stNameLbl release];
[aSong release];
[songsContainer release];
[super dealloc];
}
#end
Marcel has basically got the right answer but I think a little more explanation is needed. Look at the following lines from setSongsScrollView:
Song *thesong = [[Song alloc]init];
The above line allocates a new Song that you own and assigns a reference to it to thesong
thesong = [self.songs objectAtIndex:i];
The above line replaces that reference with a new reference to a song from the array that you don't own. Remember that: you do not own the song referenced by thesong now. There are now no more references left to the object you just allocated, but you still own it. The object has therefore leaked.
NSString *filename = [NSString stringWithFormat:#"%#/%#", [LazyImageView dataPath], [thesong.cover lastPathComponent]];
Use stringByAppendingPathComponent: to build file paths, not stringWithFormat:.
UIImageView *tempImg = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filename]];
tempImg.tag = i;
tempImg.frame = imgFrame;
[songsContainer addSubview:tempImg];
[tempImg release];
[thesong release];
The last line in the above sequence releases the object referenced by thesong. As noted above, you do not own that object. You must not release it, but you have anyway. This means that, at some point, may be now, maybe later, the object will be deallocated while something (probably the array) still thinks it has a valid reference. That's what causes the crash.
-(void)load_images{
for(int i=0;i<[songs count];i++){
Song *rsong = [[Song alloc]init];
rsong = [self.songs objectAtIndex:i];
lazyBigImg = [[LazyImageView alloc] init];
NSURL* url = [NSURL URLWithString:rsong.cover];
[lazyBigImg loadImageFromURL:url];
[lazyBigImg release];
[rsong release];
}
}
The above method contains exactly the same error.
You're creating a new Song instance (thesong), then assign this very instance to a song presumably already in the array. That makes no sense at all and is probably responsible for the memory error.
You shouldn't need to be creating new Songs if they are already in the array. Instead:
Song *thesong = [self.songs objectAtIndex:i];
Also look into using the Objective-C 2.0 for-each loop syntax.