我正在尝试从rss Feed导入数据。第一个记录插入正常,但第二个记录导致EXC_BAD_ACCESS异常。单步执行代码让我无法完成任务。失败点在于对managedObjectContext保存方法的调用。
我很感激任何帮助。
/* 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
答案 0 :(得分:1)
我很确定你的崩溃来自于此:
[self.currentElement release];
self.currentElement = nil;
基本上,这样的所有行都是错误的 - 它们应该是这样的:
self.currentElement = nil;
现在除此之外,您还需要自动释放通过属性设置的变量 - 所以此代码(以及所有类似的代码)都是错误的:
self.title = [[NSMutableString alloc] init];
self.currentElement = title;
它需要看起来像:
self.title = [NSMutableString string];
self.currentElement = title;
发生的事情是因为你将currentElement和title属性指向同一个可变字符串,当后来的代码出现时,释放currentElement AND title然后再用self.propertyname = nil释放它们,你过度释放了疯狂的对象。
内存规则非常简单 - 如果在离开方法后某些东西将“保留”某个对象,它将保留该对象,因此您不应该这样做。