Rod
Rod

Reputation: 2025

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

I have app that performs login to web service and then requests list of objects using sessionid received during Login.

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];

}

LoginOperation:

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

}

ListOperation:

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

It crash if I acces s any proeprty in any singleton object or AppDelegate. Debugger shows that singleton object or Appdelegate is valid and initialized but ANY property of that object is invalid and access leads to crash.

This is some strange threading-related gotcha. The only thing I can think of is that NSOperation has invalid copies of all other objects in it's thread or something like that.

It doesn't crash if doing same in manually spawned thread using [NSThread detachNewThreadSelector:@selector(performList) toTarget:self withObject:nil]; I want to use NSOperation instead of NSThread detach... because NSOperation provides queue.

What is the optimal pattern for such situation? defining ListOperation as Concurrent Operation? I don't want complicated mess with defining Concurrent Operation.

I think my case is fairly simple and there should be simple solution?

Upvotes: 0

Views: 798

Answers (3)

SummaGuy2023
SummaGuy2023

Reputation: 11

Try using zombies within Instruments. Really helpful link that helped me track down leaks before. Not sure how effective this will be in a threaded scenario.

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

Upvotes: 1

Peter N Lewis
Peter N Lewis

Reputation: 17811

Turn on zombies (NSZombieEnabled environment variable) to see if you are overfreeing.

Log the [[[UIApplication sharedApplication] delegate] sessionId] to verify what it is before the stringWithString (if it was nil, that would raise an exception).

Speaking of which, [NSString stringWithString:xxx] does absolutely nothing useful. Whatever you are trying to acomplish with that, it isn't going to help - reread the memory management rules.

Add an NSLog at the start/end of each main to verify they are syncronous as you expect.

And "it crashes" really is a bit too vague for a question, please include more details of the crash backtrack.

Upvotes: 0

Jason Coco
Jason Coco

Reputation: 78353

You can add one operation as a dependency for another. The other is then guaranteed not to execute until after the dependent operation completes. Also, anywhere you use the sessionID in your code, you should ensure that the Login operation has already completed. An example of adding dependencies based on your code:

- (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];
}

Now, listOperation definitely will not execute until loginOperation completes.

Upvotes: 0

Related Questions