Block literals make const copies of captured local state. The _errors
variable is a local reference -- it's not the same thing as the _errors
instance variable in the enclosing scope. The value of the _errors
reference within the block is initialized when the block is defined, not when the block is executed. That's why you're not seeing an updated value.
In general, referencing an instance variable from within a block tends to be confusing. And if it worked the way you were expecting, that would conceptually represent a significant violation of encapsulation, so perhaps it's best that it doesn't.
In any case, consider using accessor methods from within a block to access the state of an object in the enclosing scope, instead of taking a snapshot of the object's instance variable(s) by referencing them directly. More generally, when using a declared a property, prefer using the property's accessor's to directly getting and setting the underlying instance variable; that can help you avoid little pitfalls like this one.
Your rewritten block might look something like the following:
NSOperation *finishedUploading = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Completed. Errors: %@", self.errors);
self.textArea.editable = YES;
if (![self.errors isEqualToString:@""])
{
//Trim the last newline
self.errors = [self.errors substringToIndex:self.errors.length-1];
dispatch_async(dispatch_get_main_queue(), ^{
//Show error message
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
//Show success dialog
});
}
}];
Note that the block is capturing self
(which was also true when it directly accessed the ivar), so it's possible that you're creating a retain cycle. To avoid that, see SO questions on breaking block retain cycles, for example this one: Weak references in blocks and retain cycles