【问题标题】:iOS NSURLConnection (sendAsynchronousRequest:) too much cacheiOS NSURLConnection (sendAsynchronousRequest:) 缓存过多
【发布时间】:2015-02-25 01:10:19
【问题描述】:

我的应用程序中有几个内存泄漏(不!请参阅更新 1),它们都归结为异步 URLRequest。下面的代码给了我一个内存泄漏,似乎“数据”从未被释放(下面的代码在我的应用程序中逻辑上没有使用,因为它是一个完全无用的无限循环,我只是写它来显示内存泄漏。这个使使用的 RAM 在不到一秒的时间内从 5 MB 变为 20 MB。我的互联网速度确实与此相符 [仅供记录]):

- (void)start{
    NSOperationQueue *oQC = [[NSOperationQueue alloc] init];
    NSLog(@"a");
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.online-image-editor.com//styles/2014/images/example_image.png"]] queue:oQC completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        NSLog(@"b");
        [self start];
    }];
}

我也尝试过设置 data = nil,但这确实像假设的那样不起作用。 有没有人知道如何避免内存泄漏以及这是否是 NSURLConnection 的正常行为?

更新 1:

这似乎与内存泄漏无关,而是与缓存问题有关。 (感谢@rdelmar,他看到了问题,但他的解决方案不太奏效)

基于this post,我尝试在它的 .h 文件中创建一个新的“加载器”类:

#import <Foundation/Foundation.h>

@interface Loader : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>

@property NSMutableData *mData;
@property (nonatomic, copy) void (^returnBlock)(NSData *data, NSError *error);

- (id)initForWhateverWithURLString:(NSString*)urlString andHandler:(void (^)(NSData *data, NSError *error))handler;

@end

这在它的 .m 文件中:

#import "Loader.h"

@implementation Loader

@synthesize mData;

- (id)initForWhateverWithURLString:(NSString*)urlString andHandler:(void (^)(NSData *data, NSError *error))handler{
    self = [super init];
    if (self) {
        /*NSOperationQueue *oQC = [NSOperationQueue mainQueue];
        [NSURLConnection sendAsynchronousRequest:mUR queue:oQC completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
            [[NSURLCache sharedURLCache] removeCachedResponseForRequest:mUR];
            handler(nil, nil);
         }];*/
        mData = [NSMutableData new];
        self.returnBlock = handler;
        NSMutableURLRequest *mUR = [[NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60] mutableCopy];
        NSURLConnection *URLCon = [[NSURLConnection alloc] initWithRequest:mUR delegate:self];
        [URLCon start];
    }
    return self;
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{
    return nil;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [mData appendData:data];
    data = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    self.returnBlock(mData, nil);
    mData = nil;
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    self.returnBlock(nil, error);
}

@end

我也实现了:

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:@"nsurlcache"];
[NSURLCache setSharedURLCache:sharedCache];

不过,这些方法都不能帮助减少大量的 RAM 使用!

【问题讨论】:

  • 你能在雷达上提交一个错误 (bugreport.apple.com) 吗?我已经提交了一个错误报告 (19871483),看起来 iOS 8 正在泄漏 NSURLConnection。我们在我们的应用中也发现了这个问题。
  • 我已经做到了。感谢您的反馈。

标签: ios memory asynchronous memory-leaks nsurlconnection


【解决方案1】:

如果您不使用 ARC,请更改

[[NSOperationQueue alloc] init];

[[[NSOperationQueue alloc] init] autorelease];

[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.online-image-editor.com//styles/2014/images/example_image.png"]]

[[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.online-image-editor.com//styles/2014/images/example_image.png"]] autorelease]

【讨论】:

  • 我正在使用 ARC。这是我使用 ARC 时遇到的第一次重大内存泄漏,我无法解释。这就是我问的原因,真的很奇怪。
  • 泄漏的确切信息是什么
  • 没有消息。如果我不使用这些数据,使用的 RAM 就会急剧增加。泄漏仪器也没有显示任何内容。
【解决方案2】:

我不认为你看到的是泄漏。我认为内存不断增加,因为数据正在被缓存。如果您更改请求的缓存协议,问题就会消失(您将获得默认行为 NSURLRequestUseProtocolCachePolicy,通过使用 requestWithURL:)

- (void)viewDidLoad {
    [super viewDidLoad];
    self.req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.online-image-editor.com//styles/2014/images/example_image.png"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
    [self start];
}

- (void)start{
    NSOperationQueue *oQC = [NSOperationQueue mainQueue]; // this queue is where the completion block runs, so you should use mainQueue if you want to do any UI updating
    NSLog(@"a");
    [NSURLConnection sendAsynchronousRequest:self.req queue:oQC completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        NSLog(@"b");
        [self start];
    }];
}

编辑后:

在看了这个之后,我不确定为什么 sendAsynchronousRequest: 会随着时间的推移导致内存使用量增加。我使用 NSURLSession 进行了测试(无论如何我们现在都应该使用它),这似乎可以正常工作而不会导致内存增加。

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *urlString = @"http://www.online-image-editor.com//styles/2014/images/example_image.png";
    self.req = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
    [self start];
}

- (void)start{
    NSLog(@"a");
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:self.req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        self.counter ++;
        NSLog(@"counter is: %ld", self.counter);
        [self start];
    }];
    [task resume];
}

【讨论】:

  • 这似乎是正确的,但我不得不说问题仍然没有“解决”,而是“大大减少了”。 RAM 使用量仍在增加,但这种增量远没有以前那么剧烈。
  • OK 在尝试了一段时间并在网上搜索了一些之后,我发现这没有帮助。查看我在主帖中的更新以获取更多信息。
  • @user2456014,我用一种我认为效果更好的方法更新了我的答案。下载了几百次后,我没有发现内存使用量有任何增加。
  • 是的,这更好,并且在多次请求后也给我 0 MB RAM 增加。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-25
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多