The following code snippet uses GCD to compute a set of integers and store them in an array.
factArray = {1!, 2!, ... n!} where k! designates factorial(k)=k*(k-1)*...*2*1.
I wonder why I can add objects to the factArray variable (instance of NSMutableArray) inside the block though factArray isn't declared with the __block qualifier.
NSUInteger n = 10;
NSMutableArray *factArray = [[NSMutableArray alloc] initWithCapacity:n];
__block NSUInteger temp = 1;
dispatch_apply(n,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^(size_t s) {
NSUInteger w;
temp *= floor(s) + 1;
w = temp;
[factArray addObject:@(w)];
});
__block NSArray *sortedArray;
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
sortedArray = [factArray sortedArrayUsingComparator:^NSComparisonResult(NSNumber *n1, NSNumber *n2) {
return [n1 compare:n2];
}];
NSLog(@"%@", sortedArray);
});
Of course, this code still works if we add the __block qualifier.
You're confusing variables and objects. Variables point to objects, but a variable is distinct from the object it points to. The
__block
storage specifier affects variable storage, but doesn't really have any effect on the object pointed to by the variable. The object could be pointed to by any number of variables in addition to that one, and it wouldn't care what their storage looked like — it's just floating out in the heap while they point to it.So, in short, you are not changing the variable — you're mutating the object.
factArray
is a variable, liketemp
. It's a pointer; it holds the memory address of something else. The Block gets a copy of that pointer, just like it gets a copy oftemp
. The object that's pointed to, though, isn't copied. It stays in the same place, and remains anNSMutableArray
. You can send messages to it through the pointer; that doesn't change the pointer's value. It still points to the same place, and the contents of an object can be modified without changing the pointer.If you wanted to get rid of that existing array and make a new one, and call that array
factArray
:then you would be changing the pointer's value, and then you would need the
__block
specifier.Colloquially, since ObjC objects can only be accessed via pointers, we often refer to the pointer as if it were the object. The distinction is largely unimportant; this is one of the times it is.