I am trying to import data from an rss feed. The first record is inserted fine, but the second result in a EXC_BAD_ACCESS exception. Stepping through the code has gotten me no close to figuring things out. The failure point is on the call to the managedObjectContext save method.
I appreciate any help with this.
/* Workout.h */
#import <UIKit/UIKit.h>
@class Workout;
@interface WorkoutsController : UITableViewController <NSXMLParserDelegate> {
NSFetchedResultsController *_fetchedResultsController;
NSURLConnection *urlConnection;
NSMutableData *xmlData;
Workout *currentWorkout;
NSMutableString *title;
NSMutableString *link;
NSMutableString *details;
NSMutableString *currentElement;
}
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSURLConnection *urlConnection;
@property (nonatomic, retain) NSMutableData *xmlData;
@property (nonatomic, retain) Workout *currentWorkout;
@property (nonatomic, retain) NSMutableString *title;
@property (nonatomic, retain) NSMutableString *link;
@property (nonatomic, retain) NSMutableString *details;
@property (nonatomic, retain) NSMutableString *currentElement;
@end
/* Workout.m */
/**
* Determine if the current element is an 'item'
* <item>
* <title>...</title>
* <link>...</link>
* <content:encoded>...</content:encoded>
*/
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
// determine when parser is inside an item element
if ([elementName isEqualToString:@"item"]) {
self.currentWorkout = [[Workout alloc] initWithEntity:[[self.fetchedResultsController fetchRequest] entity]
insertIntoManagedObjectContext:[self.fetchedResultsController managedObjectContext]];
}
// only read child elements of the item element
if (self.currentWorkout != nil) {
if ([elementName isEqualToString:@"title"]) {
self.title = [[NSMutableString alloc] init];
self.currentElement = title;
}
else if ([elementName isEqualToString:@"link"]) {
self.link = [[NSMutableString alloc] init];
self.currentElement = link;
}
else if ([elementName isEqualToString:@"content:encoded"]) {
self.details = [[NSMutableString alloc] init];
self.currentElement = details;
}
}
}
/**
* Finished reading the tag content
*/
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// only read child elements of the item element
if (self.currentWorkout != nil) {
[self.currentElement appendString:string];
}
}
/**
* Extract the text for the following tags
* <item>
* <title>...</title>
* <link>...</link>
* <content:encoded>...</content:encoded>
*/
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
// determine if the item element is being closed
// if so save the workout
if ([elementName isEqualToString:@"item"]) {
self.currentWorkout.title = self.title;
self.currentWorkout.url = self.link;
self.currentWorkout.details = self.details;
NSLog(@"Completing: %@", self.currentWorkout.title);
NSError *error;
NSManagedObjectContext *moc = [self.fetchedResultsController managedObjectContext];
/*** Line 206: Fails Here ***/
if (![moc save:&error]) {
NSLog(@"Failed to save to data store: %@ - %@",
[error localizedDescription], [error userInfo]);
}
[self.currentElement release];
self.currentElement = nil;
[self.title release];
self.title = nil;
[self.link release];
self.link = nil;
[self.details release];
self.details = nil;
[self.currentWorkout release];
self.currentWorkout = nil;
}
}
/* Backtrace */
(gdb) bt
#0 0x027b6903 in objc_msgSend ()
#1 0x00000007 in ?? ()
#2 0x023a2688 in _NSQLRow_dealloc_standard ()
#3 0x026730eb in __CFBasicHashRemoveValue ()
#4 0x0258a1e0 in CFBasicHashRemoveValue ()
#5 0x0259f7c8 in CFDictionaryRemoveValue ()
#6 0x02441724 in -[NSSQLCore managedObjectContextDidUnregisterObjectsWithIDs:] ()
#7 0x0243524a in -[NSPersistentStoreCoordinator(_NSInternalMethods) _informAffectedStoresOfInterestByChildContextInObjectsWithObjectIDs:withSelector:] ()
#8 0x0242e940 in -[NSPersistentStoreCoordinator(_NSInternalMethods) managedObjectContextDidUnregisterObjectsWithIDs:] ()
#9 0x02384396 in -[_PFManagedObjectReferenceQueue _processReferenceQueue:] ()
#10 0x023837f4 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] ()
#11 0x023bce55 in -[NSManagedObjectContext save:] ()
#12 0x000038e5 in -[WorkoutsController parser:didEndElement:namespaceURI:qualifiedName:] (self=0x633ca10, _cmd=0x178994, parser=0x632a0c0, elementName=0x634a850, namespaceURI=0x0, qName=0x0) at /Users/chris/Documents/Projects/iPhone/WorkoutApp/Classes/WorkoutsController.m:206
#13 0x000f13a9 in _endElementNs ()
#14 0x02ae6ea7 in xmlParseXMLDecl ()
#15 0x02af1bb1 in xmlParseChunk ()
#16 0x000f0baa in -[NSXMLParser parse] ()
#17 0x00003352 in -[WorkoutsController connectionDidFinishLoading:] (self=0x633ca10, _cmd=0x17ce32, connection=0x6343510) at /Users/chris/Documents/Projects/iPhone/WorkoutApp/Classes/WorkoutsController.m:132
#18 0x00059b96 in -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] ()
#19 0x00059aef in _NSURLConnectionDidFinishLoading ()
#20 0x02c0d72f in URLConnectionClient::_clientDidFinishLoading ()
#21 0x02cd8fcf in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload ()
#22 0x02c02968 in URLConnectionClient::processEvents ()
#23 0x02c027e5 in MultiplexerSource::perform ()
#24 0x0263afaf in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#25 0x0259939b in __CFRunLoopDoSources0 ()
#26 0x02598896 in __CFRunLoopRun ()
#27 0x02598350 in CFRunLoopRunSpecific ()
#28 0x02598271 in CFRunLoopRunInMode ()
#29 0x02f3800c in GSEventRunModal ()
#30 0x02f380d1 in GSEventRun ()
#31 0x002c6af2 in UIApplicationMain ()
#32 0x000021b0 in main (argc=1, argv=0xbfffefdc) at /Users/chris/Documents/Projects/iPhone/WorkoutApp/main.m:14
I am pretty sure your crash is from this:
[self.currentElement release];
self.currentElement = nil;
Basically, all the lines like that are wrong - they should look like this:
self.currentElement = nil;
Now in addition to that, you also need to autorelease variables you set via properties - so this code (and all the code like it) is wrong:
self.title = [[NSMutableString alloc] init];
self.currentElement = title;
It needs to look like:
self.title = [NSMutableString string];
self.currentElement = title;
What's happening is because you are pointing the currentElement and title property to the same mutable string, when the later code came along, releasing both currentElement AND title and then releasing both again with self.propertyname = nil, you were over-releasing the objects like mad.
The memory rules are really simple - if something is going to "hold" an object after you leave a method, it will retain that object so you should not.
User contributions licensed under CC BY-SA 3.0