【问题标题】:How to access other objects from within NSOperation? Threading issues lead to crash如何从 NSOperation 中访问其他对象?线程问题导致崩溃
【发布时间】:2009-06-28 13:25:44
【问题描述】:

我的应用程序执行登录到 Web 服务,然后使用登录期间收到的 sessionid 请求对象列表。

Appdelegate.h

....
@property (nonatomic, retain) NSString *sessionId;

AppDelegate.m:

-(id)init{
        queue = [[NSOperationQueue alloc] init];
        [queue setMaxConcurrentOperationCount:1];
.....
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
        LoginOperation *loginOperation = [[LoginOperation alloc] init];
        [queue addOperation:loginOperation];
        [loginOperation release];
      ListOperation *listOperation = [[ListOperation alloc] init];
      [queue addOperation:listOperation];
      [listOperation release];

}

登录操作:

-(void) main {
...
[[UIApplication sharedApplication] delegate] setSessionId:sessionID];
...

}

列表操作:

-(void)main{
//Crashes at next line:
NSString *sessionId = [[UIApplication sharedApplication] delegate] sessionId] ;
}

如果我访问任何单例对象或 AppDelegate 中的任何属性,它会崩溃。调试器显示单例对象或 Appdelegate 有效且已初始化,但该对象的任何属性均无效且访问会导致崩溃。

这是一些与线程相关的奇怪问题。我唯一能想到的是 NSOperation 在它的线程或类似的东西中有所有其他对象的无效副本。

如果使用 [NSThread detachNewThreadSelector:@selector(performList) toTarget:self withObject:nil] 在手动生成的线程中执行相同操作,它不会崩溃; 我想使用 NSOperation 而不是 NSThread detach... 因为 NSOperation 提供队列。

这种情况的最佳模式是什么?将 ListOperation 定义为并发操作?我不想复杂的定义并发操作。

我认为我的情况很简单,应该有简单的解决方案?

【问题讨论】:

  • 听起来像是竞争条件或过度释放的对象。什么是创建 sessionID?什么是崩溃?回溯?这里没有足够的信息来调试它。
  • 调试器显示我正在访问的对象是有效的,但该对象的所有属性都无效。我试图从 NSOperation 中访问一些单例对象,它会产生相同的崩溃条件。因此 BAD_ACCESS 崩溃。
  • 我试图用 start() 方法和所有东西使它成为一个并发 NSOperation。手册说并发是在新线程中执行的。所以我认为这可能会解决问题。但事实并非如此。崩溃完全一样!

标签: objective-c iphone


【解决方案1】:

尝试在 Instruments 中使用僵尸。非常有用的链接,帮助我之前追踪泄漏。不确定这在线程场景中的效果如何。

http://www.markj.net/iphone-memory-debug-nszombie/

【讨论】:

    【解决方案2】:

    打开僵尸(NSZombieEnabled 环境变量)看看你是否过度释放。

    记录 [[[UIApplication sharedApplication] delegate] sessionId] 以验证它在 stringWithString 之前是什么(如果它是 nil,则会引发异常)。

    说到这里,[NSString stringWithString:xxx] 绝对没有任何用处。无论您想完成什么,它都无济于事 - 重新阅读memory management rules

    在每个 main 的开始/结束处添加一个 NSLog 以验证它们是否如您所期望的那样同步。

    而且“它崩溃”对于一个问题来说确实有点太模糊了,请提供更多关于崩溃回溯的细节。

    【讨论】:

    • 记录 [[[UIApplication sharedApplication] delegate] sessionId] 导致 BAD ACCESS 崩溃。但是 Appdelegate 是有效的对象!这是非常奇怪的问题。
    • @Roman - 这意味着您的 sessionID 属性被过度释放。按照 bbum 的要求,将代码发布到您创建实际 sessionID 的位置。
    • 打开 NSZombieEnabled(在您的可执行文件设置的参数面板中,添加一个环境变量 NSZombieEnabled = YES。另外,编辑您的问题并显示所有引用 sessionID 的代码。您可能处理不当。
    【解决方案3】:

    您可以添加一个操作作为另一个操作的依赖项。然后保证在从属操作完成之前不执行另一个。此外,在代码中使用 sessionID 的任何地方,都应确保登录操作已经完成。根据您的代码添加依赖项的示例:

    - (void)applicationDidFinishLaunching:(UIApplication *)application {
          LoginOperation *loginOperation = [[LoginOperation alloc] init];
          ListOperation *listOperation = [[ListOperation alloc] init];
          [listOperation addDependency:loginOperation];
          [queue addOperation:loginOperation];
          [queue addOperation:listOperation];
          [loginOperation release];
          [listOperation release];
    }
    

    现在,listOperationloginOperation 完成之前肯定不会执行。

    【讨论】:

    • 感谢您的提示。但是它并不能解决我从 NSOperation 内部访问 sessionID 的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    • 1970-01-01
    相关资源
    最近更新 更多