【问题标题】:Objective-C thread safe code to prevent a crash用于防止崩溃的 Objective-C 线程安全代码
【发布时间】:2012-02-20 16:24:09
【问题描述】:

我收到了一份带有 SIGSEGV 的 iPhone 崩溃报告,我想我已经缩小了可能的原因并找到了解决方案。 由于线程导致的崩溃很难调试,因此我无法重现此问题,但可以对我的假设提供一些帮助 - 是否合理?

我的代码使用 ASIHttpRequest 通过 ASINetWorkQueue 下载一组文件。这是一个简化的示例

//initialize download queue and do this code block in a loop for each file

NSURL *fileURL = [NSURL URLWithString:...
__block ASIHTTPRequest *fileRequest = [ASIHTTPRequest requestWithURL:fileURL];

[fileRequest setCompletionBlock:^{
   //do some stuff   
}];
[fileRequest setFailedBlock:^{
    NSString *someError = [NSString stringWithFormat:...
    [self someErrorMethod:someError];       
}];

[downloadQueue addOperation:...

-(void)someErrorMethod(NSString *errorMessage) {
    DDLogWarn(errorMessage);

    if ([self downloadQueue]) {
        for (ASIHTTPRequest *request in [[self downloadQueue] operations]) {
            [request clearDelegatesAndCancel];
        }
        [[self downloadQueue] reset];
    }
 }

崩溃报告的前两行是

  • libobjc.A.dylib 0x31846fbc objc_msgSend + 15
  • MyApp 0x0002cab5 -[Myapp someErrorMethod:] (MyApp.m:)

我对为什么会发生这种情况的想法

  • 文件下载失败,调用失败的块
  • 它遍历每个请求并清除委托并取消它们,然后重置队列
  • 但是,在运行前,另一个文件下载失败,进入失败块回调
  • 但是,由于它现在已被取消,其失败的块已被释放
  • 当代码尝试记录错误消息时,它的内存已被释放,并且会出现不可预知的结果

这有意义吗?由于我是 Objective-C 的新手,我的分析是正确的还是我遗漏了一些明显的东西?

我正在考虑使用锁来使 errorMethod 线程安全,希望它能解决这个问题。根据上面的代码,这听起来像是正确的解决方案吗?

谢谢

【问题讨论】:

  • 不确定您的错误,但您可能想检查一下:stackoverflow.com/a/5023583/330494 您应该使用 blocksafeSelf 来引用 self with an ivar 块。
  • 谢谢 Barlow 我在这里使用了一个永远不会被释放的单例类,所以我认为保留周期不是问题,对吧?

标签: objective-c ios crash thread-safety block


【解决方案1】:

这听起来不太可能。 ASIHttpRequest 可能在同一个线程上执行所有回调(我对此相当肯定)。

如果我不得不猜测,您的错误更有可能出现在这一行:

DDLogWarn(errorMessage);

DDLogWarn 的第一个参数是格式,而不是字符串。在 errorMessage 包含 % 的任何情况下,这都可能会崩溃。你的意思是:

DDLogWarn(@"%@", errorMessage);

由于DDLogWarn() 是一个可变参数方法,它将开始用它在堆栈中找到的(随机)值替换字符串中的任何 % 替换值。它将读取堆栈,直到您用完 % 替换。如果任何 % 替换是基于指针的(如 %s 或 %@),那么它将跟随指针指向随机位置。

SEG_ACCERR 表示您请求了一块您不拥有的内存。 SEG_MAPERR 表示您请求了一块未映射的内存。要么是遵循完全随机指针的预期结果。

【讨论】:

  • 感谢罗布的回复。这确实是我错过的一些愚蠢的事情。但是,这会导致 SEGV_ACCERR 吗?我试过用字符串在%至摄制,并得到了SEGV_MAPERR代替libobjc.A.dylib 0x0262509b objc_msgSend + 15的CoreFoundation 0x0245f6f8 __CFStringAppendFormatCore的CoreFoundation 0x023aab6c _CFStringCreateWithFormatAndArgumentsAux基金会0x0137f1a5 - [NSPlaceholderString initWithFormat:区域:论点:]基金会0x013cc66e - [的NSString initWithFormat:参数:] MyApp 0x00062867 +[DDLog log:level:flag:context:file:function:line:format:]
  • 已更新;任何一种形式的 SEGV 都是预期的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2021-12-08
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多