【问题标题】:Implicit conversion of a non-Objective-C pointer type void* to NSString*__strong* is disallowed with ARCARC 不允许将非 Objective-C 指针类型 void* 隐式转换为 NSString*__strong*
【发布时间】:2013-07-02 19:19:40
【问题描述】:

迁移到 ARC 时出现上述错误。代码如下:

static NSString *cashBalanceKeyPath = @"test";

...

[xxx forKeyPath:cashBalanceKeyPath options:NSKeyValueObservingOptionNew context:&cashBalanceKeyPath];

...

-(void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if (&cashBalanceKeyPath == context)   < error here
    {
      ...
    }

当我使用桥接器时:

if (&cashBalanceKeyPath == (__bridge NSString *)context)

我收到了错误:Comparison of distinct pointer types (NSString *__strong* and NSString *)

如何进行转换?提前致谢。

【问题讨论】:

  • 这个比较是否适用于 MRC?
  • 是的。比较适用于 MRC(没有 ARC)。可以隐式转换。
  • 原始比较 &amp;cashBalanceKeyPath == context 即使在 ARC 下也看起来不错。您没有比较任何对象,甚至没有将对象转换为普通指针。原来的编译错误是什么?

标签: ios objective-c cocoa automatic-ref-counting


【解决方案1】:

我无法确切告诉您原因,但如果您交换比较顺序,您不会收到警告或错误:

if (context == &cashBalanceKeyPath) {
    // ...      
}

【讨论】:

  • 恶心!你是对的,我也不知道为什么 - 错误或 C 转换规则(在任何其他语言中,人们不会认为这是一种选择,但在 C 系列中......)。我不建议依赖这个。
  • 这是我的假设/猜测== 的右侧被转换为左侧的类型。 ARC 允许将NSString ** 转换为void *,但禁止相反的方向。
  • 这很有趣,因为原始的比较看起来是正确的,不应该发出错误。交换操作数可以消除错误。
  • 我相信顺序很重要。 (context == &cashBalanceKeyPath) 是 c 指针比较。 (&cashBalanceKeyPath == context) 是 NSSting 指针比较。在第一种情况下您不需要转换,但在后一种情况下您确实需要转换。
  • 检查了标准。操作数的顺序应该重要,任何指向“对象”的指针(即在 C 意义上而不是 Obj-C 意义上)都可以与void * 进行比较。我会说这是 ARC 逻辑的扭曲。你会从我的回答中看到,添加一个明确的void * 演员表是可行的——你不应该在这里需要一座桥。我们似乎让编译器不对称地处理对称操作。 @MartinR,也许是错误报告?
【解决方案2】:

您似乎将变量的 地址 用作唯一标记,因此这里不存在内存管理/所有权问题。要进行地址比较,请将变量的地址转换为 void:

if ((void *)&cashBalanceKeyPath == context)

这似乎为编译器提供了它所需要的一切,而无需任何桥接。

【讨论】:

  • 对。事实上,问题作者没有分享导致桥接的原始错误/警告消息。也许它只是不兼容的指针?
  • @iMartin:我认为原始错误消息在问题标题中。
【解决方案3】:

如果你去掉错误消息中的__strong,就会更清楚发生了什么:

Comparison of distinct pointer types (NSString ** and NSString *)

&amp;cashBalanceKeyPath 是指向 NSString 对象或 NSString** 的指针,而上下文被强制转换为 NSString* 或普通 NSString 对象(它不是)。

所以要解决这个问题,请将演员表更改为 (NSString * const *),显然需要 const 来安抚 ARC。

【讨论】:

  • if (&cashBalanceKeyPath == (__bridge NSString **)context) 我得到了错误:指向非常量类型 NSString * 的指针没有明确的所有权
  • 这给出了“错误:指向非常量类型'NSString *'的指针,没有明确的所有权”
  • @user2543991 是的,这里犯了一个错误。更新为现在使用正确的演员表
  • const 是错误的指针所有权属性。 ARC 期待 __autoreleasing,
【解决方案4】:

因为cashBalanceKeyPath 是一个指针,context 是一个指针,所以比较这两者的正确方法是:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == (__bridge void *)(cashBalanceKeyPath)) {

    }
}

电话应该是:

[xxx addObserver:self forKeyPath:cashBalanceKeyPath options:0 context:(__bridge void *)(cashBalanceKeyPath)];

我想知道您的代码如何与 MRC 一起使用。

【讨论】:

  • context 期望包含对象的地址,而不是对象本身。你的比较永远不会过去。
  • 编辑后:是的,如果他将对象本身用作context,您的解决方案将是正确的。但是,他正在使用对象的地址(指向对象的指针)。
  • 你是对的,但我认为以这种方式使用指针是荒谬的。
  • 为什么?他避免搭桥。该字符串是静态的,因此无论如何都没有生命周期管理。
  • 是的,但是&amp;cashBalanceKeyPath 的内容是什么?它完全随机。 cashBalanceKeyPath 是指针。 &amp;cashBalanceKeyPath 只是一些你不知道的地址。这可以是任何东西。
【解决方案5】:

整个问题大概可以通过写来避免

static int cashBalanceKeyPathContext = 0;

并使用 &cashBalanceKeyPathContext 作为上下文。

【讨论】:

    【解决方案6】:

    您收到错误的原因是因为您正在比较一个字符串和一个指向字符串的指针,而您实际上只是想比较两个字符串。当你比较两个字符串时,你应该使用isEqualToString。所以你的代码可能看起来像这样:

    NSString *contextString = (__bridge NSString *)context;
    if ([contextString isEqualToString:cashBalanceKeyPath])
    {
        //Do something
    }
    ...
    

    希望这会有所帮助!

    【讨论】:

    • 如果我正确理解了这个问题,他不想比较字符串。 contextcashBalanceKeyPath 变量的地址,仅用作唯一指针。
    • 抱歉,误解了这个特定的问题。我以前遇到过这个问题并用这个解决了它,但正如你所指出的那样,我的情况有所不同。
    【解决方案7】:

    如果你想比较字符串,你应该使用 isEqualToString 方法:

    【讨论】:

    • 投反对票是因为他对字符串相等性不感兴趣。在 observeValueForKeyPath 中传递了一个需要识别的上下文。上下文可以是任何东西。为简单起见,他选择将静态变量的地址作为上下文传递,并尝试检查上下文是否与静态变量的地址匹配。
    • 很公平!感谢您的澄清。
    【解决方案8】:

    ARC 在字符串方面通常不喜欢 __strong,Apple 建议您使用 copy。

    【讨论】:

    • "copy" 可用于 NSString property,但这是一个完全不相关的话题。我在问题中没有看到任何属性声明。
    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 2011-10-15
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多