Threading issues with ivars
Threading issues with ivars
- Subject: Threading issues with ivars
- From: Andreas Grosam <email@hidden>
- Date: Tue, 2 Feb 2010 13:49:49 +0100
Hello,
I have the following issue:
The code below shows a brief snippet of a view controller. Its responsibility - besides managing the views - is to create a URL request, and using a UIConnection to download data. Then, the data - a JSON format - will be parsed. The result is a dictionary from which I need certain fields which in turn shall be displayed in labels residing in the view controllers view.
The URL request will be done in a separate thread and yields data which is actually a JSON format (not shown in the code snipped).
The parsing will be performed within yet another thread. Its main method is shown below.
The JSON parser returns an NSDictionary instance from which I need certain fields. These values will be used to set the text property of labels which reside in the view controller.
There is a label "nameLabel" which text needs to be set from a certain field in the dictionary. I don't want to set the label's text property directly in the main thread's method - instead I use an NSString instance called "name" to store the text. This is an ivar, see property declaration below.
Before the thread is finished and returns, it schedules the method -upadateLabels on the main thread which finally sets the label's text property (shown below).
Here is the issue:
Once the auto release pool gets released, the ivar "name" becomes invalid - as if it has been deallocated by the pool.
I don't see why this should happen, since I think I get a copy of the string - as the property declaration implies: @property (copy) NSString* name.
Do I miss something fundamentally?
I need to mention, this is code on the iPhone - no GC
Thanks in advance for pointing me to the solution.
Regards
Andreas
// MainViewController.m
@interface MainViewController ()
@property (nonatomic, retain) IBOutlet UILabel* nameLabel;
@property (copy) NSString* name;
@end
@implementation MainViewController
@synthesize name;
@synthesize nameLabel;
- (void)threadMain:(NSData *)data
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString* jsonResponse = nil;
SBJsonParser* parser = nil;
@try {
jsonResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
parser = [[SBJsonParser alloc] init];
id jsonObject = [parser objectWithString:jsonResponse];
NSDictionary* feature = [(NSArray*)[jsonObject objectForKey:@"features"] objectAtIndex:0];
self.name = [[feature objectForKey:@"properties"] objectForKey:@"name"];
if (jsonObject) {
[self performSelectorOnMainThread:@selector(updateLabels) withObject:nil waitUntilDone:NO];
}
}
@catch (NSException * ex) {
<snip>
}
@finally {
[jsonResponse release];
[parser release];
[pool release];
}
}
- (void) updateLabels
{
self.nameLabel.text = self.name;
}
One *important* observations is here:
Before generating the URL request, I actually need a parameter which is asked from the user via an interface.
When the user starts to edit the input (a UITextField) the view controller gets notified through a method, shown below.
The purpose of this method is to clear the previous results.
** IFF I do not set the text property to nil, the NSString instance "name" remains valid. So, it seems, that the string object will be *shared* - but not copied. Hence the auto release pool does not dealloc the string. The label's text property is declared as: @property(nonatomic, copy) NSString* text
This looks strange to me. Any thoughts?
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
// User entered editing: clear labels:
self.nameLabel = nil; // if uncommented, the ivar "name" remains valid
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden