问题
I am using the drupal-ios-sdk (based on AFNetworking) and my app has a Tab Bar Controller created with storyboard. When loading one of the view controllers I am creating a request in initWithCoder with drupal-ios-sdk and assigning an instance variable in the success block. Later in viewDidLoad I try to print this variable and I'm interested in why I have to retain the instance variable in the success block, even if I define the variable with autorelease.
This is not ARC!
Not using retain in the success block
My VC.h
@interface AboutViewController : UIViewController {
@private
NSDictionary *response;
NSString *aboutPageHTML;
}
@end
My VC.m
-(id) initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
NSDictionary *viewData = [NSMutableDictionary new];
[viewData setValue:@"aboutse" forKey:@"view_name"];
aboutPageHTML = [[[NSString alloc]init] autorelease];
void(^successBlock)(AFHTTPRequestOperation*, id) =
^(AFHTTPRequestOperation *operation, id responseObject) {
response = [responseObject copy];
aboutPageHTML = [response valueForKey:@"body"];
NSLog(@"%s - %@", __PRETTY_FUNCTION__, aboutPageHTML);
[aboutPageHTML retain]; // critical!
};
[DIOSView viewGet:viewData success:successBlock
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%s, %@", __PRETTY_FUNCTION__, error);
}];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"%s - %@", __PRETTY_FUNCTION__, aboutPageHTML);
NSLog(@"%s - %f %f", __PRETTY_FUNCTION__, self.view.bounds.size.width, self.view.bounds.size.height);
}
Edit:
declaring the variable with __block does not seem to make a difference. How come?
回答1:
There are many things wrong with this code. aboutPageHTML is an instance variable that you want a strong reference to (i.e. should be retained). In aboutPageHTML = [[[NSString alloc]init] autorelease]; you are not maintaining a strong reference to it. This is incorrect.
And later on, in your success block (it is irrelevant that it is a block; it's just any code that runs later), you do aboutPageHTML = [response valueForKey:@"body"]; [aboutPageHTML retain]; which does retain the object stored in that instance variable. So you are being inconsistent with the memory management for the same instance variable in two places.
Also, when you assign another value to a strongly-referenced variable, you should make sure to release the previous value, which you are not doing. This goes for both aboutPageHTML and response.
Finally, the object pointed to by viewData is leaked, as you have a strong reference to it (you use new) but don't release it.
Also, you should use setObject:forKey: and objectForKey: for dictionaries. And you need to declare a mutable dictionary when you want a dictionary you can change. (This is probably why you (incorrectly) decided to use setValue:forKey:)
So in conclusion, this would be more like it:
-(id) initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
NSMutableDictionary *viewData = [NSMutableDictionary new];
[viewData setObject:@"aboutse" forKey:@"view_name"];
aboutPageHTML = [[NSString alloc] init];
void(^successBlock)(AFHTTPRequestOperation*, id) =
^(AFHTTPRequestOperation *operation, id responseObject) {
[response release];
response = [responseObject copy];
[aboutPageHTML release];
aboutPageHTML = [[response objectForKey:@"body"] retain];
};
[DIOSView viewGet:viewData success:successBlock
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%s, %@", __PRETTY_FUNCTION__, error);
}];
[viewData release];
}
return self;
}
来源:https://stackoverflow.com/questions/15540348/block-execution-ios-and-assigning-variable