Objective c 区块和中央调度,代码上的差异?

Objective c 区块和中央调度,代码上的差异?,objective-c,objective-c-blocks,grand-central-dispatch,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 = [NSM

这些例子有什么不同?我不明白为什么它们不同,提供不同的结果。正如我所看到的,块中的代码将在某个时候在主线程中运行,第一个代码提供的结果是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"];
这是相当微妙的(也就是说,最好构造代码以避免回答以下问题:)

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

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

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

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

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

区别在于:

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

  • 在第二种情况下,您有一个对象,
    NSMutableString
    myString
    始终指向该对象。但是,该
    NSMutableString
    的内容将从
    的“foo”
    更改为
    的“bar”

因此,在第一种情况下,块在指向
@“foo”
时捕获
myString
。稍后将其指向
@“bar”
的更改不会影响块中捕获的副本

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

顺便说一下,这与
调度\u 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"
区别在于:

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

  • 在第二种情况下,您有一个对象,
    NSMutableString
    myString
    始终指向该对象。但是,该
    NSMutableString
    的内容将从
    的“foo”
    更改为
    的“bar”

因此,在第一种情况下,块在指向
@“foo”
时捕获
myString
。稍后将其指向
@“bar”
的更改不会影响块中捕获的副本

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

顺便说一下,这与
调度\u 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"

下面是首次创建块并调用
dispatch\u async
时的情况:

    --NSString-------
    |     "Foo"     |
    -----------------
      ^      ^
      |      |
myString    GCD Block
下面是它在函数末尾的表现。您正在将
myString
分配给一个全新的NSString实例,与块捕获的实例不同:

    --NSString-------  --NSString-------
    |     "Foo"     |  |     "Bar"     |
    -----------------  -----------------
             ^             ^
             |             |
       GCD Block          myString
    --NSMutableString----
    |     "Bar"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block
在这种情况下,无论何时执行块,块都将始终打印“Foo”

第二个例子类似地开始:

    --NSMutableString----
    |     "Foo"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block
除了修改块捕获的相同NSMutableString实例外:

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

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

以下是首次创建块并调用
dispatch\u async
时的情况:

    --NSString-------
    |     "Foo"     |
    -----------------
      ^      ^
      |      |
myString    GCD Block
下面是它在函数末尾的表现。您正在将
myString
分配给一个全新的NSString实例,与块捕获的实例不同:

    --NSString-------  --NSString-------
    |     "Foo"     |  |     "Bar"     |
    -----------------  -----------------
             ^             ^
             |             |
       GCD Block          myString
    --NSMutableString----
    |     "Bar"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block
在这种情况下,无论何时执行块,块都将始终打印“Foo”

第二个例子类似地开始:

    --NSMutableString----
    |     "Foo"         |
    ---------------------
      ^      ^
      |      |
myString    GCD Block
除了修改块捕获的相同NSMutableString实例外:

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

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

欢迎来到多线程世界。这实际上不是多线程问题。所有这些代码都可以在主线程上运行。欢迎来到多线程世界。这真的不是多线程问题。所有这些代码都可以在主线程上运行。