【问题标题】:Using a pointer to an object declared outside a block, inside the block使用指向在块外声明的对象的指针,在块内
【发布时间】:2013-11-11 01:11:21
【问题描述】:

我正在尝试在块本身内部使用在 Objective-C 块之外声明的对象的指针。例如:

NSError* error = nil;
[self invokeAsync:^id{
    return [self doSomething:&error];
}];

我在第三行得到一个编译器错误,告诉我:

将 'NSError *const__strong *' 发送到 'NSError 类型的参数 *__autoreleasing *' 改变指针的保留/释放属性

为什么会这样?

【问题讨论】:

    标签: objective-c pointers compiler-errors objective-c-blocks


    【解决方案1】:

    编译器消息令人困惑,但它告诉您类型不匹配。

    但是,没关系,因为那个代码没有意义。

    异步调用无法在调用线程的堆栈中设置状态。 IE。无法将error 设置为有意义的值。

    也就是说,方法invokeAsync:会在工作块执行之前返回。因此,无法从invokeAsAsync: 返回任何有意义的信息来指示块执行的成功/失败。


    如果你想异步调用一些错误,你需要一个回调:

    [self invokeAsync:^id{
        NSError *e;
        if ([self doSomething:&e])
            [self errorHappened:e];
        else
            [self asyncThingyDone];
    }];
    

    【讨论】:

      【解决方案2】:

      这里有两个问题。首先是@bbum 已经指出的时间问题。

      另一个可能是您所要求的,即为什么编译器会给出这样的错误。同样正如@bbum 所说,“编译器消息令人困惑”。为了将第二个问题与第一个问题分离,假设您的呼叫是invokeSyncAndWait: 而不是invokeAsync:。现在时间问题已经解决了,我们可以专注于第二个问题:

      NSError* error = nil;
      [self invokeSyncAndWait:^id{
          return [self doSomething:&error];
      }];
      

      块中捕获的error 变量只是一个按值复制,而不是真正的引用:

      封闭词法范围的本地堆栈(非静态)变量是 捕获为 const 变量。它们的值取自 程序中的块表达式。在嵌套块中,值 从最近的封闭范围捕获。

      因为你没有真正引用块中的变量error,所以你不能取它的地址。这就是编译器拒绝编译您的代码的原因。

      要获取引用变量,您应该使用__block

      使用声明的封闭词法范围的局部变量 __block 存储修饰符由引用提供,因此是可变的。任何更改都会反映在封闭的词法范围中,包括 在同一封闭词法范围内定义的任何其他块。 这些在“__block 存储类型”中有更详细的讨论。

      所以工作代码是:

      __block NSError* error = nil;
      [self invokeSyncAndWait:^id{
          return [self doSomething:&error];
      }];
      

      虽然它仍然是危险的代码:

      因此,__block 变量的地址可以随时间变化。

      我刚刚解释了编译问题。

      【讨论】:

      猜你喜欢
      • 2014-12-01
      • 1970-01-01
      • 2020-04-03
      • 2016-03-04
      • 2014-09-09
      • 1970-01-01
      • 1970-01-01
      • 2022-08-16
      • 1970-01-01
      相关资源
      最近更新 更多