gpt4 book ai didi

ios - 在循环中使用 dataWithContentsOfURL 内存泄漏

转载 作者:塔克拉玛干 更新时间:2023-11-02 09:07:21 24 4
gpt4 key购买 nike

我正在使用 Xcode 4.6.3 和 iOS 5.5/6.1.6。

我正在使用后台线程将大量 jpg 从服务器加载到 iOS 设备。

dispatch_async(kBgQueue, ^
{
// get the array of filenames to download
NSURL* url = [NSURL URLWithString:webPath];
NSArray* theArray = [NSArray arrayWithContentsOfURL:url];
if( theArray )
{
dispatch_async(dispatch_get_main_queue(), ^{
// disable screen buttons
[self setButtons:false];
});

[self loadImagesFromList:theArray sourceBundle:bundlePath destBundle:localBundlePath manager:manager];

if (!stopFlag) {
// if no memory error has occurred
NSLog(@"calling refresh after load_images");
dispatch_async(dispatch_get_main_queue(), ^{
[self refresh];
});
}
theArray = nil;
}
else
{
NSLog(@"Error loading bundle");
}
});

后台方法:

-(void)loadImagesFromList:(NSArray *)theArray
sourceBundle:(NSString *)bundlePath
destBundle:(NSString *)localBundlePath
manager:(NSFileManager *)manager {

// initialize the progress and activity indicator
dispatch_async(dispatch_get_main_queue(), ^{
[self.activityIndictor startAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self.progressIndictor setProgress:0 animated:NO];
});

NSURL *url;
NSString *srcFile;
NSString *destFile;
NSError *error = nil;

int counter = 0;
float prog = 0;
float increment = 1.0 / [theArray count];
float stepSize = [theArray count] / 10;

for (NSString *file in theArray)
{
if (stopFlag) {
NSLog(@"I see stopFlag = true, counter = %d, prog = %f", counter, prog);
return;
}
srcFile = [bundlePath stringByAppendingPathComponent:file];
destFile = [localBundlePath stringByAppendingPathComponent:file];

counter += 1;
prog += increment;
if (counter == stepSize) {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressIndictor.progress = prog;
});
counter = 0;
}

// only download if file isn't already here
BOOL fileExists = [manager fileExistsAtPath:destFile]; // check if we already have it
if (!fileExists) {
// jpg or folder check
if ([[destFile pathExtension] isEqualToString:@"jpg"]) {
url = [NSURL URLWithString:srcFile];
data = [NSData dataWithContentsOfURL:url
options:0
error:&error];

[data writeToFile:destFile options:NSDataWritingAtomic error:&error];
data = nil;
} else {
[manager createDirectoryAtPath:destFile withIntermediateDirectories:YES attributes:nil error:&error];
}
}
}
}

如果文件存在,循环将压缩数组并返回主线程。如果缺少任何文件,下载/写入部分似乎会占用 RAM 并导致触发内存不足警告。需要数千个文件才能完成。

我试过在循环外声明变量,甚至在主线程中执行所有操作以测试这是否导致泄漏。我尝试使用备用 dataWithContentsOfURL:options:error 调用。我试过 Instruments,但它真的很慢而且经常崩溃。在崩溃之前,它确实显示分配在缓慢上升、上升、上升。

几天后,我被难住了。

最佳答案

我建议的第一件事是使用 @autoreleasepool 来控制消耗的内存峰值量。现在,您正在将内容作为自动释放对象下载到 NSData 中,完成后,您将 nil-ing 该变量,简单地将其标记为一旦自动释放池被耗尽(在 loadImagesFromList 完成之前不会发生),就会被释放。通过 (a) 将变量声明移动到 for 循环内; (b) 将其包装在 @autoreleasepool 中,您的内存将在各个下载完成时被释放。

-(void)loadImagesFromList:(NSArray *)theArray
sourceBundle:(NSString *)bundlePath
destBundle:(NSString *)localBundlePath
manager:(NSFileManager *)manager {

// initialize the progress and activity indicator
dispatch_async(dispatch_get_main_queue(), ^{
// your UI update here
});

int counter = 0;
float prog = 0;
float increment = 1.0 / [theArray count];
float stepSize = [theArray count] / 10;

for (NSString *file in theArray)
{
@autoreleasepool {
if (stopFlag) {
NSLog(@"I see stopFlag = true, counter = %d, prog = %f", counter, prog);
return;
}

NSString *srcFile = [bundlePath stringByAppendingPathComponent:file];
NSString *destFile = [localBundlePath stringByAppendingPathComponent:file];

counter += 1;
prog += increment;
if (counter == stepSize) {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressIndictor.progress = prog;
});
counter = 0;
}

// only download if file isn't already here
BOOL fileExists = [manager fileExistsAtPath:destFile]; // check if we already have it
if (!fileExists) {
NSError *error = nil;

// jpg or folder check
if ([[destFile pathExtension] isEqualToString:@"jpg"]) {
NSURL *url = [NSURL URLWithString:srcFile];
NSData *data = [NSData dataWithContentsOfURL:url
options:0
error:&error];

[data writeToFile:destFile options:NSDataWritingAtomic error:&error];
} else {
[manager createDirectoryAtPath:destFile withIntermediateDirectories:YES attributes:nil error:&error];
}
}
}
}
}

关于ios - 在循环中使用 dataWithContentsOfURL 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23919684/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com