关于Objective C:如何从NSOperation内部访问其他对象?线程问题导致崩溃

 2021-04-27 

How to access other objects from within NSOperation? Threading issues lead to crash

我有一个应用程序,该应用程序执行登录到Web服务的操作,然后使用在登录期间收到的sessionid来请求对象列表。

Appdelegate.h

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

AppDelegate.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-(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];

}

登录操作:

1
2
3
4
5
6
-(void) main {
...
[[UIApplication sharedApplication] delegate] setSessionId:sessionID];
...

}

ListOperation:

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

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

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

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

这种情况的最佳模式是什么?将ListOperation定义为并发操作?我不希望在定义并发操作时遇到麻烦。

我认为我的案子很简单,应该有简单的解决方法吗?


尝试在Instruments中使用僵尸。真正有用的链接,之前帮助我跟踪了泄漏情况。不确定在线程化方案中这将如何有效。

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


打开僵尸(NSZombieEnabled环境变量)以查看是否释放过多。

登录[[[[UIApplication sharedApplication]委托] sessionId],以验证stringWithString之前的内容(如果为nil,则将引发异常)。

说起来,[NSString stringWithString:xxx]绝对没有任何用处。无论您要完成什么,它都无济于事-重新读取内存管理规则。

在每个主节点的开头/末尾添加一个NSLog,以验证它们是否符合您的期望。

"崩溃"确实有点含糊不清,请提供崩溃回溯的更多详细信息。


您可以将一个操作添加为另一个操作的依赖项。这样就保证了另一个不会执行,直到相关操作完成为止。另外,在代码中使用sessionID的任何地方,都应确保"登录"操作已完成。根据您的代码添加依赖项的示例:

1
2
3
4
5
6
7
8
9
- (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];
}

现在,listOperation绝对不会执行,直到loginOperation完成。