1

这些例子有什么区别?我无法弄清楚为什么它们不同并提供不同的结果。如我所见,块中的代码有时会在主线程中运行,而第一个代码提供的结果是 foo 或 bar,不知道为什么以及何时。

NSString *myString = @"foo";
dispatch_async (dispatch_get_main_queue(), ^{
    NSLog (@"%@", myString); 
});
myString = @"bar";

第二:

NSMutableString *myString = [NSMutableString stringWithString:@"foo"]; 
dispatch_async (dispatch_get_main_queue(), ^{
    NSLog (@"%@", myString); 
});
[myString setString:@"bar"];
4

3 回答 3

4

这是非常微妙的(即,最好构造代码以避免需要回答这个问题:))

在第一个示例中,该块捕获指向文字常量 NSString 的指针的 const 副本。然后更新原始指针以指向新字符串。该块应该稍后从主线程中的某个任意点打印“foo”。

在第二个示例中,该块捕获指向可变 NSString 的指针的 const 副本。然后可变的 NSString 被更新为具有不同的内容。如果代码在非主线程/队列上运行,则块可能会打印“foo”,可能会打印“bar”,或者可能由于在更改时打印字符串而崩溃。如果块在主线程/队列上,那么它将打印“bar”。

于 2013-01-01T20:47:11.040 回答
3

区别在于:

  • 在第一种情况下,您有两个不同的对象,@"foo"并且@"bar". myString首先指向@"foo",然后将其更改为指向@"bar"

  • 在第二种情况下,您有一个对象,一个NSMutableString. myString一直指向那个对象。但是,那个变化的内容NSMutableString,从"foo""bar"

当您创建一个块时,它会从封闭范围中捕获它使用的任何局部变量的值。 因此,在第一种情况下,块myString在指向@"foo". 稍后将其指向的更改@"bar"不会影响块中捕获的副本。

在第二种情况下,该块捕获 的值myString。但是,它不会捕获myString指向的对象的状态。因此,您可以更改对象的内容,并且块在运行时会看到新内容。

dispatch_async顺便说一句,这与GCD 或多线程无关。如果您直接同步运行该块,您会看到相同的效果。

NSString *myString = @"foo";
void (^myBlock)(void) = ^{
    NSLog (@"%@", myString); 
};
myBlock(); // prints "foo"
myString = @"bar";
myBlock(); // prints "foo"


NSMutableString *myString = [NSMutableString stringWithString:@"foo"]; 
void (^myBlock)(void) = ^{
    NSLog (@"%@", myString); 
};
myBlock(); // prints "foo"
[myString setString:@"bar"];
myBlock(); // prints "bar"
于 2013-01-01T20:50:20.280 回答
2

这是您第一次创建块并调用时的样子dispatch_async

    --NSString-------
    |     "Foo"     |
    -----------------
      ^      ^
      |      |
myString    GCD Block

下面是它在函数末尾的样子。您正在分配myString一个全新的 NSString 实例,与块捕获的实例不同:

    --NSString-------  --NSString-------
    |     "Foo"     |  |     "Bar"     |
    -----------------  -----------------
             ^             ^
             |             |
       GCD Block          myString

在这种情况下,无论何时执行该块,该块将始终打印“Foo”。

第二个例子以类似的方式开始:

    --NSMutableString----
    |     "Foo"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block

除非您正在修改块捕获的相同 NSMutableString 实例:

    --NSMutableString----
    |     "Bar"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block

该块可以打印“Foo”或“Bar”,具体取决于它何时执行。如果块打印“Bar”,则表示该块是在您修改 NSMutableString 实例后执行的。

于 2013-01-01T21:05:11.560 回答