我正在创建一个任务(NSOperation)并将其放入NSOperationQueue
TaskJsonParser *parseTask = [[TaskJsonParser alloc] initWithJsonString:responseString andDelegate:self];
[self.opQueue addOperation:parseTask];
当任务完成时,它调用委托方法并将其标志设置为“已完成”。但是仪器显示它仍然在内存中...并且表明上面的代码是它的创建者。
为什么队列在操作完成后不释放它。没有其他强烈的参考......
这是NSOperation的代码
@interface TaskJsonParser ()
@property (strong, nonatomic) NSString *stringToParse;
@property (strong, nonatomic) SBJson4Parser *jsonParser;
@end
@implementation TaskJsonParser
#pragma mark - Custom initialization
- (instancetype)initWithJsonString:(NSString *)jsonString andDelegate:(id<JsonParsingDelegate>) delegate
{
self = [super init];
if (self) {
_delegate = delegate;
_stringToParse = jsonString;
self.TAG = @"TaskJsonParse";
// configure the parser
SBJson4ValueBlock block = ^(id v, BOOL *stop) {
BOOL isDictionary = [v isKindOfClass:[NSDictionary class]];
if (isDictionary) {
NSDictionary *parseResult = (NSDictionary *)v;
// [self.delegate didFinishParsingJsonWithResult:parseResult];
[(NSObject *)self.delegate performSelector:@selector(didFinishParsingJsonWithResult:) withObject:parseResult];
} else {
NSLog(@"json parsing did not result in a NSDictionary, returnig %@",NSStringFromClass([v class]));
[(NSObject *)self.delegate performSelector:@selector(didFinishParsingJsonWithResult:) withObject:v];
// [self.delegate didFinishParsingJsonWithResult:v];
}
};
SBJson4ErrorBlock errorBlock = ^(NSError* err) {
NSLog(@"OOPS parsing error: %@", err);
MvpError *e = [[MvpError alloc] initWithErrorObject:err andType:Parser];
// [self.delegate didFailToParseJsonWithError:e];
[(NSObject *)self.delegate performSelector:@selector(didFinishParsingJsonWithResult:) withObject:e];
};
_jsonParser = [SBJson4Parser multiRootParserWithBlock:block
errorHandler:errorBlock];
if (debugLog) { NSLog(@"Allocating Task: %@;",self.TAG); }
}
return self;
}
#pragma mark - Overriden NSObject methods
// requierd for concurrent running
- (void)main
{
@autoreleasepool {
if (self.isCancelled) {
[self completeOperation];
return;
}
SBJson4ParserStatus responseCode = [self.jsonParser parse:[self.stringToParse dataUsingEncoding:NSUTF8StringEncoding]];
if (responseCode == SBJson4ParserComplete) {
NSLog(@"parse complete");
} else if (responseCode == SBJson4ParserError) {
NSLog(@"failed to parse");
}
[self completeOperation];
}
}
init ...方法中的thous块会导致问题吗?
答案 0 :(得分:1)
你有一个强大的参考周期。具体来说,您有代码说:
SBJson4ValueBlock block = ^(id v, BOOL *stop) {
BOOL isDictionary = [v isKindOfClass:[NSDictionary class]];
if (isDictionary) {
NSDictionary *parseResult = (NSDictionary *)v;
// [self.delegate didFinishParsingJsonWithResult:parseResult];
[(NSObject *)self.delegate performSelector:@selector(didFinishParsingJsonWithResult:) withObject:parseResult];
} else {
NSLog(@"json parsing did not result in a NSDictionary, returnig %@",NSStringFromClass([v class]));
[(NSObject *)self.delegate performSelector:@selector(didFinishParsingJsonWithResult:) withObject:v];
// [self.delegate didFinishParsingJsonWithResult:v];
}
};
因此,该操作维护对JSON解析器的强引用,但解析器使用一个块,该块本身维护一个强引用回操作。
您可以使用weakSelf
模式:
typeof(self) __weak weakSelf = self;
SBJson4ValueBlock block = ^(id v, BOOL *stop) {
BOOL isDictionary = [v isKindOfClass:[NSDictionary class]];
if (isDictionary) {
NSDictionary *parseResult = (NSDictionary *)v;
[weakSelf.delegate didFinishParsingJsonWithResult:parseResult];
} else {
NSLog(@"json parsing did not result in a NSDictionary, returnig %@",NSStringFromClass([v class]));
[weakSelf.delegate didFinishParsingJsonWithResult:v];
}
};
底线,不要在self
属性的块内使用strong
,否则您将避免强引用周期。在错误块中重复此编辑。
或者,我注意到您已将JSON解析器设为类属性。因为parse
同步运行,这是不必要的,并且您可以使解析器成为main
的局部变量,这也可以解决您的强引用周期,而不需要上述weakSelf
模式。 / p>
下面,请在您的代码示例之前找到我最初提供的总法律顾问。问题是第2点的第一个问题。
这类问题有两个常见的来源:
如果这是并发操作,请记得发布isFinished
KVN,例如,在更改_finished
ivar时,请执行以下操作:
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
当然,你也有isFinished
方法:
- (BOOL)isFinished
{
return _finished;
}
也可以使用executing
重复此过程。
就我个人而言,我将这个逻辑包装在executing
和finished
属性中,如果需要,我可以分享这些属性,但我想把这个答案集中在基本要求上(你有一个{{ 1}}方法并发布isFinished
KVN)。
有关更多详细信息,请参阅并发编程指南的Operation Queues chapter中的配置并发执行操作部分。
确保操作本身内没有强大的参考周期(例如保留周期)。常见的强参考周期包括:
类属性,它们是显式引用isFinished
的块,或通过引用某些ivar隐式执行此操作;
在终止操作之前忽略调用self
的重复计时器;或
意外定义为invalidate
的任何自引用属性(例如委托)。
在Instruments中,您可以使用“记录引用计数”功能(在this answer的后半部分中描述)来确定哪些内容(如果有的话)保持对您的操作的强引用。
< / LI> 醇>