块和中央调度,代码差异?

时间:2013-01-01 20:36:47

标签: objective-c objective-c-blocks grand-central-dispatch

这些例子有什么不同?我无法弄清楚为什么它们不同并提供不同的结果。我看到,块中的代码是在某个时候在主线程中运行,第一个代码提供的结果是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"];

3 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:3)

区别在于:

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

  • 在第二种情况下,您有一个对象NSMutableStringmyString始终指向该对象。但是,NSMutableString内容"foo"更改为"bar"

When you create a block, it captures the values of any local variables that it uses from the enclosing scope.因此,在第一种情况下,该块在指向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"

答案 2 :(得分: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实例后执行了块。