【问题标题】:Using autorelease variables in an iOS background thread在 iOS 后台线程中使用自动释放变量
【发布时间】:2013-09-10 16:06:21
【问题描述】:

在一个 iOS 应用程序中,我启动了几个后台线程来处理一些从 REST 服务返回的 XML。

我有一些用户在 PeopleParser.m 中的 [self.names addObject: name] 代码行遇到间歇性崩溃。崩溃日志没有说明原因,只有崩溃的代码行。我无法重现崩溃,所以我假设它与内存有关。在我的 for 循环完成之前,我的 *xml 对象是否可能被主线程池释放?请注意,我没有在后台线程中声明自动释放池。

Fetcher.m

-(void) peopleFetchComplete:(ASIHTTPRequest *)theRequest {

    dispatch_async( backgroundQueue, ^{
       PeopleParser *xmlParse = [[PeopleParser alloc] initWithContext:[self managedObjectContext]];
       [xmlParse parseXMLData:[theRequest responseData] parseError:&parseError];
       [xmlParse release];
    });
}

PeopleParser.h

@interface PeopleParser : NSObject {
    NSMutableArray *names;
    ...
}

-(void)parseXMLData:(NSData *)data parseError:(NSError **)error;

@property (retain, nonatomic) NSMutableArray *names;

PeopleParser.m

-(id)initWithContext:(NSManagedObjectContext *)managedObjContext{
    self = [super init];
    self.managedObjectContext = managedObjContext;
    names = [[NSMutableArray alloc] init];
    return self;
}

-(void)dealloc{
    [names release];
    [managedObjectContext release];
}

@synthesize names;

-(void)parseXMLData {

    //documentWithData returns an autorelease object
    SMXMLDocument *xml = [SMXMLDocument documentWithData:someNSData error:nil];
    NSArray *people = [[document root] children];

    for (SMXMLElement *element in people) {
        NSString *name = [element attributeNamed:@"personName"];
        [self.names addObject: name];  //CRASHES HERE occasionally 
    }

    //do additional stuff with the data
    ...
}

崩溃日志

异常类型:EXC_CRASH (SIGABRT) 异常代码:0x0000000000000000, 0x0000000000000000 崩溃的线程:7

最后一个异常回溯:

0 CoreFoundation 0x3465229e __exceptionPreprocess + 158

1 libobjc.A.dylib 0x3c37a97a objc_exception_throw + 26

2 CoreFoundation 0x3459c8d4 -[__NSArrayM insertObject:atIndex:] + 764

3 MyApp 0x000fee36 -[PeopleParser parseXMLData:parseError:] (PeopleParser.m:62)

4 MyApp 0x000e9b4c __50-[Fetcher peopleFetchComplete:]_block_invoke (Fetcher.m:818)

【问题讨论】:

  • 来吧,这不是真正的代码。对dispatch_async 的调用中没有右括号。 -initWithContext: 被声明为返回 id 但没有返回语句。如果您有异常,而不是崩溃,请打印异常的内容。
  • 抱歉打错字了 - 我正在消除与我试图指出的问题无关的东西,主要是 NSLog 语句和不相关的对象,以使代码更易于阅读(我假设没有一个人要我发布一个 800 行的课程)。我进行了编辑以纠正这些事情。另外,我没有例外,因为这是我无法在调试器中重现的错误。崩溃日志就是这样 - 我希望 Apple 能提供更详细的信息,但事实并非如此。

标签: ios objective-c multithreading pool autorelease


【解决方案1】:

“self.names”有可能在块执行之前被释放。 确保取消阻塞操作或保护此类不被释放(通过使用加载屏幕阻塞屏幕),以便用户无法返回。

它可能发生在例如 unloadView 或类似的地方(如果您粘贴更多代码,它可能会更准确)。

基于此,我认为异常是从 insertObject 方法调用的 - 这意味着您最有可能尝试插入“nil”对象。在将它添加到数组之前尝试添加 if(name) { } - 在这种情况下,XML 文件可能有问题。

【讨论】:

  • 不,不是。 self 在它被创建的点被块捕获 - 在-(void) doFoo 中,导致额外的retain 在它上面。然而,可能不是线程安全的是对 self.names 的访问
  • 请参阅编辑。我在问题中添加了大量代码,以及崩溃报告。抱歉,我之前没有添加这个,我试图限制范围并保持简单。
  • 好吧,我认为异常是从 insertObject 方法调用的——这意味着您最有可能尝试插入“nil”对象。尝试在将其添加到数组之前添加 if(name) { } - 在这种情况下,XML 文件可能有问题。
  • 我认为你是对的 - 我将代码行更改为 [self.names addObject: nil];并收到了一个非常相似的崩溃日志。我必须定期从我的 REST 服务中获取错误的 XML。请在上面编辑您的答案以匹配您的评论,我将单击复选标记。谢谢!
猜你喜欢
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
  • 2012-03-06
  • 2016-08-31
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多