NSOperationQueue完成后不释放操作

时间:2014-07-29 13:56:12

标签: objective-c nsoperationqueue

我正在创建一个任务(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块会导致问题吗?

1 个答案:

答案 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点的第一个问题。


这类问题有两个常见的来源:

  1. 如果这是并发操作,请记得发布isFinished KVN,例如,在更改_finished ivar时,请执行以下操作:

    [self willChangeValueForKey:@"isFinished"];
    _finished = YES;
    [self didChangeValueForKey:@"isFinished"];
    

    当然,你也有isFinished方法:

    - (BOOL)isFinished
    {
        return _finished;
    }
    

    也可以使用executing重复此过程。

    就我个人而言,我将这个逻辑包装在executingfinished属性中,如果需要,我可以分享这些属性,但我想把这个答案集中在基本要求上(你有一个{{ 1}}方法并发布isFinished KVN)。

    有关更多详细信息,请参阅并发编程指南的Operation Queues chapter中的配置并发执行操作部分。

  2. 确保操作本身内没有强大的参考周期(例如保留周期)。常见的强参考周期包括:

    • 类属性,它们是显式引用isFinished的块,或通过引用某些ivar隐式执行此操作;

    • 在终止操作之前忽略调用self的重复计时器;或

    • 意外定义为invalidate的任何自引用属性(例如委托)。

    在Instruments中,您可以使用“记录引用计数”功能(在this answer的后半部分中描述)来确定哪些内容(如果有的话)保持对您的操作的强引用。

    < / LI>