質問

I'm familiar with the __block statement that makes the variable 'assignable' within a Block. But I see that when using some of Objective-C features that uses Blocks as Arguments in Methods, some variables are assignable, even if they are not declared with this __block statement.

Here are 2 codes for example:

[UIView animateWithDuration:2 animations:^
     {
         self.animatedView.backgroundColor = [UIColor blueColor];
         self.animatedView.center = CGPointMake(100, 100);
     }];

(animatedView is a simple UIView connected with an IBOutlet).

    int myInt = 10;
    NSMutableString* mString = [NSMutableString stringWithString:@"Mutable Hello"];
    NSString* imString = @"Imutable Hello";

    void (^myBlock)(void) = ^
    {
        [mString appendString:@" Block"]; //working
        imString = @"Imutable Hello Block"; //error
        myInt = 11; //error
    };

My question is: How come I can assign values to the UIView instance properties?

I'm not addressing an Object and changing it, like my mString.

I would expect the 'center' property to behave like my myInt, as it's a C struct accessed directly, and not a pointer to an object.

I would expect 'backgroundColor' to behave like my imString, as it's a pointer to an object which is assigned with a new object, isn't it?

I couldn't find a satisfying explanation in the documentation... I would appreciate if anyone can provide one, or address me to one.

役に立ちましたか?

解決

This is the difference between assignment and usage. Usage being method calls. You are entirely permitted to call methods on an instance ([mString appendString:@" Block"]; //working) but you can't assign (imString = @"Imutable Hello Block"; //error) without tagging the variables to tell the compiler that it should enable it.

This code:

self.animatedView.backgroundColor = [UIColor blueColor];

is still not really an assignment, it's a 'hidden' method call. Dot notation is never an assignment, it's syntactic sugar for method calls. It actually translates to:

[[self animatedView] setBackgroundColor:[UIColor blueColor]];

The difference between assigning to local variables and to variables inside an object is the location in memory that they reside at. Basically, will they exist for long enough to be useful. It's the difference between data on the stack and on the heap.

他のヒント

To allow a variable to be changed within a block, you use the _block storage type modifier—see “The _block Storage Type.”

__block NSString* imString = @"Imutable Hello";

Reference by apple doc

The following rules apply to variables used within a block:

  1. Global variables are accessible, including static variables that exist within the enclosing lexical scope.
  2. Parameters passed to the block are accessible (just like parameters to a function). Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.
  3. Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope.

  4. Variables local to the enclosing lexical scope declared with the __block storage modifier are provided by reference and so are mutable.

  5. Any changes are reflected in the enclosing lexical scope, including any other blocks defined within the same enclosing lexical scope. These are discussed in more detail in “The __block Storage Type.”

  6. Local variables declared within the lexical scope of the block, which behave exactly like local variables in a function.

  7. Each invocation of the block provides a new copy of that variable. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block.

In your first example the block "captures" the variable self - which is a pointer to a retainable object. You don't modify self itself in your example when you write:

self.someProperty = someValue;

self's value still remains the same - that is, it still points to the same object.

You would modify self for example if you write:

self = nil;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top