XMLフィードを解析し、その結果をコアデータに格納するアプリケーションに問題があります。NSXMLParserを使用してXMLデータをコアデータストアに解析するときにメモリが蓄積する
この問題は、ストアに何もなく、フィード全体が解析されて保存されているときにアプリの初回実行時にのみ発生します。 問題は、メモリ割り当てが50%の試行でアプリケーションをクラッシュさせるまで、通常は約10Mbで構築されるまでです。 割り当てられたオブジェクトはCFData(ストア)オブジェクトのようですが、強制的に解放する方法はありません。私たちは、コードに入る前に、 は、あなたがそれを構文解析を完了し、コアデータに保存一度、正常に実行するために得ることができた場合、後続のすべての打ち上げは結構です、メモリ使用量がここ2.5MB
を超えたことがない私が持っている一般的なアプローチです: ゲットNSDataオブジェクトへのフィードNSFileManagerを使用してファイルとして保存します。 ファイルパスからURLを作成し、それをparseXMLFile:メソッドに渡します。代議員は自己です。 到達パーサー:didStartElement:namespaceURI:qualifiedName:attributes:必要なタグからデータを取得するための辞書を作成します。 パーサー:foundCharacters:メソッドは、タグの内容を文字列に保存します パーサー:didEndElement:...メソッドは、タグが必要なものかどうかを判断します。もしそうなら、辞書を無視しなければそれを辞書に追加します。アイテムの終わりに達すると、それをコアデータストアに追加するメソッドが呼び出されます。
ここでサンプルコードや他の人の投稿を見ると、一般的なアプローチには何も間違っているようです。
コードは以下のとおりですが、それはビューコントローラのより大きなコンテキストから来ていますが、直接関係のないものは省略しました。
私は試したことの点で: フィードはXMLであり、JSONに変換するオプションはありません。 共有文書領域に見つかって保存されている画像ではありません。それが何であるかについての
手がかり:責任
オブジェクトアドレスカテゴリの作成時間ライブサイズ : は、これは私が割り当てられた最大の、最も数多くのものに楽器から取得するエントリ(項目ごとに256K)であります図書館責任発信者
1 0xd710000 CFData (店舗)16024774912 262144 CFNetworkはURLConnectionClient :: clientDidReceiveData•( _CFData のconst *、 URLConnectionClient :: ClientConnectionEventQueue *)
そして、ここにコンテンツの匿名性のために編集されたコードは、です;)
-(void)parserDidStartDocument:(NSXMLParser *)feedParser { }
-(void)parserDidEndDocument:(NSXMLParser *)feedParser { }
-(void)parser:(NSXMLParser *)feedParser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
eachElement = elementName;
if ([eachElement isEqualToString:@"item" ])
{
//create a dictionary to store each item from the XML feed
self.currentItem = [[[NSMutableDictionary alloc] init] autorelease];
}
}
-(void)parser:(NSXMLParser *)feedParser foundCharacters:(NSString *)feedString
{
//Make sure that tag content doesn't line break unnecessarily
if (self.currentString == nil)
{
self.currentString = [[[NSMutableString alloc] init]autorelease];
}
[self.currentString appendString:feedString];
}
-(void)parser:(NSXMLParser *)feedParser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
eachElement = elementName;
NSString *tempString = [self.currentString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([eachElement isEqualToString:@"title"])
{
//skip the intro title
if (![tempString isEqualToString:@"Andy Panda UK"])
{
//add item to di citonary output to console
[self.currentItem setValue:tempString forKey:eachElement];
}
}
if ([eachElement isEqualToString:@"link"])
{
//skip the intro link
if (![tempString isEqualToString:@"http://andypanda.co.uk/comic"])
{
//add item to dicitonary output to console
[self.currentItem setValue:tempString forKey:eachElement];
}
}
if ([eachElement isEqualToString:@"pubDate"])
{
//add item to dicitonary output to console
[self.currentItem setValue:tempString forKey:eachElement];
}
if ([eachElement isEqualToString:@"description"])
{
if ([tempString length] > 150)
{
//trims the string to just give us the link to the image file
NSRange firstPart = [tempString rangeOfString:@"src"];
NSString *firstString = [tempString substringFromIndex:firstPart.location+5];
NSString *secondString;
NSString *separatorString = @"\"";
NSScanner *aScanner = [NSScanner scannerWithString:firstString];
[aScanner scanUpToString:separatorString intoString:&secondString];
//trims the string further to give us just the credits
NSRange secondPart = [firstString rangeOfString:@"title="];
NSString *thirdString = [firstString substringFromIndex:secondPart.location+7];
thirdString = [thirdString substringToIndex:[thirdString length] - 12];
NSString *fourthString= [secondString substringFromIndex:35];
//add the items to the dictionary and output to console
[self.currentItem setValue:secondString forKey:@"imageURL"];
[self.currentItem setValue:thirdString forKey:@"credits"];
[self.currentItem setValue:fourthString forKey:@"imagePreviewURL"];
//safety sake set unneeded objects to nil before scope rules kick in to release them
firstString = nil;
secondString = nil;
thirdString = nil;
}
tempString = nil;
}
//close the feed and release all the little objects! Fly be free!
if ([eachElement isEqualToString:@"item" ])
{
//get the date sorted
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss ZZZZ";
NSDate *pubDate = [formatter dateFromString:[currentItem valueForKey:@"pubDate"]];
[formatter release];
NSArray *fetchedArray = [[NSArray alloc] initWithArray:[fetchedResultsController fetchedObjects]];
//build the string to make the image
NSString *previewURL = [@"http://andypanda.co.uk/comic/comics-rss/" stringByAppendingString:[self.currentItem valueForKey:@"imagePreviewURL"]];
if ([fetchedArray count] == 0)
{
[self sendToCoreDataStoreWithDate:pubDate andPreview:previewURL];
}
else
{
int i, matches = 0;
for (i = 0; i < [fetchedArray count]; i++)
{
if ([[self.currentItem valueForKey:@"title"] isEqualToString:[[fetchedArray objectAtIndex:i] valueForKey:@"stripTitle"]])
{
matches++;
}
}
if (matches == 0)
{
[self sendToCoreDataStoreWithDate:pubDate andPreview:previewURL];
}
}
previewURL = nil;
[previewURL release];
[fetchedArray release];
}
self.currentString = nil;
}
- (void)sendToCoreDataStoreWithDate:(NSDate*)pubDate andPreview:(NSString*)previewURL {
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
[newManagedObject setValue:[[currentItem valueForKey:@"title"] description] forKey:@"stripTitle"];
[newManagedObject setValue:[[currentItem valueForKey:@"credits"] description] forKey:@"stripCredits"];
[newManagedObject setValue:[[currentItem valueForKey:@"imageURL"] description] forKey:@"stripImgURL"];
[newManagedObject setValue:[[currentItem valueForKey:@"link"] description] forKey:@"stripURL"];
[newManagedObject setValue:pubDate forKey:@"stripPubDate"];
[newManagedObject setValue:@"NO" forKey:@"stripBookmark"];
//**THE NEW SYSTEM**
NSString *destinationPath = [(AndyPadAppDelegate *)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory];
NSString *guidPreview = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *guidImage = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *dpPreview = [destinationPath stringByAppendingPathComponent:guidPreview];
NSString *dpImage = [destinationPath stringByAppendingPathComponent:guidImage];
NSData *previewD = [NSData dataWithContentsOfURL:[NSURL URLWithString:previewURL]];
NSData *imageD = [NSData dataWithContentsOfURL:[NSURL URLWithString:[currentItem valueForKey:@"imageURL"]]];
//NSError *error = nil;
[[NSFileManager defaultManager] createFileAtPath:dpPreview contents:previewD attributes:nil];
[[NSFileManager defaultManager] createFileAtPath:dpImage contents:imageD attributes:nil];
//TODO: BETTER ERROR HANDLING WHEN COMPLETED APP
[newManagedObject setValue:dpPreview forKey:@"stripLocalPreviewPath"];
[newManagedObject setValue:dpImage forKey:@"stripLocalImagePath"];
[newManagedObject release];
before++;
[self.currentItem removeAllObjects];
self.currentItem = nil;
[self.currentItem release];
[xmlParserPool drain];
self.xmlParserPool = [[NSAutoreleasePool alloc] init];
}
[EDIT] @Rog 私は一緒に遊んでみましたNSOperationしかし、これまでの運は、同じ私、oryは、すべてのすべての約256k、同じアイテムを構築します。ここでは、コードです:あなたの問題はここにある
- (void)sendToCoreDataStoreWithDate:(NSDate*)pubDate andPreview:(NSString*)previewURL
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
[newManagedObject setValue:[[currentItem valueForKey:@"title"] description] forKey:@"stripTitle"];
[newManagedObject setValue:[[currentItem valueForKey:@"credits"] description] forKey:@"stripCredits"];
[newManagedObject setValue:[[currentItem valueForKey:@"imageURL"] description] forKey:@"stripImgURL"];
[newManagedObject setValue:[[currentItem valueForKey:@"link"] description] forKey:@"stripURL"];
[newManagedObject setValue:pubDate forKey:@"stripPubDate"];
[newManagedObject setValue:@"NO" forKey:@"stripBookmark"];
NSString *destinationPath = [(AndyPadAppDelegate *)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory];
NSString *guidPreview = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *guidImage = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *dpPreview = [destinationPath stringByAppendingPathComponent:guidPreview];
NSString *dpImage = [destinationPath stringByAppendingPathComponent:guidImage];
//Create an array and send the contents off to be dispatched to an operation queue
NSArray *previewArray = [NSArray arrayWithObjects:dpPreview, previewURL, nil];
NSOperation *prevOp = [self taskWithData:previewArray];
[prevOp start];
//Create an array and send the contents off to be dispatched to an operation queue
NSArray *imageArray = [NSArray arrayWithObjects:dpImage, [currentItem valueForKey:@"imageURL"], nil];
NSOperation *imagOp = [self taskWithData:imageArray];
[imagOp start];
[newManagedObject setValue:dpPreview forKey:@"stripLocalPreviewPath"];
[newManagedObject setValue:dpImage forKey:@"stripLocalImagePath"];
//[newManagedObject release]; **recommended by stackoverflow answer
before++;
[self.currentItem removeAllObjects];
self.currentItem = nil;
[self.currentItem release];
[xmlParserPool drain];
self.xmlParserPool = [[NSAutoreleasePool alloc] init];
}
- (NSOperation*)taskWithData:(id)data
{
NSInvocationOperation* theOp = [[[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(threadedImageDownload:)
object:data] autorelease];
return theOp;
}
- (void)threadedImageDownload:(id)data
{
NSURL *urlFromArray1 = [NSURL URLWithString:[data objectAtIndex:1]];
NSString *stringFromArray0 = [NSString stringWithString:[data objectAtIndex:0]];
NSData *imageFile = [NSData dataWithContentsOfURL:urlFromArray1];
[[NSFileManager defaultManager] createFileAtPath:stringFromArray0
contents:imageFile
attributes:nil];
//-=====0jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjmn **OLEG**
}
ええ、コードの挿入機能はちょうど私のコードでうまく再生されませんので、スニペット内にスニペットがあります。ごめんなさい。私はHTMLを責めます;) – Cocoadelica