我的应用程序中有几个内存泄漏(NO!请参阅Update 1),它们都归结为异步URLRequest。下面的代码给我一个内存泄漏,它似乎是数据'永远不会发布(下面的代码在我的应用程序中逻辑上没有使用,因为它是一个完全无用的无限循环,我只是写它来显示内存泄漏。这使得使用的RAM在不到一秒的时间内从5到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我尝试创建一个新的“Loader”#39;在它的.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使用!
答案 0 :(得分:3)
我不认为你所看到的是泄漏。我认为内存不断增加,因为数据正在被缓存。如果您更改了请求的缓存协议,则问题就会消失(您正在使用requestWithURL获取默认行为NSURLRequestUseProtocolCachePolicy:)
- (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];
}
答案 1 :(得分:0)
如果您不使用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]