user2543991
user2543991

Reputation: 625

Implicit conversion of a non-Objective-C pointer type void* to NSString*__strong* is disallowed with ARC

I got the above error when migrate to ARC. Here is the code:

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
    {
      ...
    }

When I used bridge:

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

I got the error: Comparison of distinct pointer types (NSString *__strong* and NSString *)

How can I make the conversion? Thanks in advance.

Upvotes: 6

Views: 6943

Answers (8)

gnasher729
gnasher729

Reputation: 52548

The whole problem can probably be avoided by writing

static int cashBalanceKeyPathContext = 0;

and using &cashBalanceKeyPathContext as the context.

Upvotes: 0

Adrian Sluyters
Adrian Sluyters

Reputation: 2241

ARC generally doesn't like __strong when it comes to string and Apple recommend that you use copy.

Upvotes: -1

uchuugaka
uchuugaka

Reputation: 12782

If you want to compare strings you should be using the method isEqualToString:

Upvotes: -1

cobbal
cobbal

Reputation: 70753

If you strip out the __strong in the error message, it's clearer what's going on:

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

&cashBalanceKeyPath is a pointer to an NSString object, or a NSString**, while context is being cast to an NSString*, or a plain NSString object (which it isn't).

So to fix the problem, change the cast to be (NSString * const *), the const is apparently required to appease ARC.

Upvotes: 1

Jonathan Cichon
Jonathan Cichon

Reputation: 4406

as cashBalanceKeyPath is a pointer and context is a pointer the correct way to compare this two is:

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

    }
}

and the call should be:

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

I wonder how your code could work with MRC.

Upvotes: 0

CRD
CRD

Reputation: 53000

You appear to be using the address of a variable as a unique tag, so there are no memory management/ownership issues here. To do the address comparison cast the address of the variable to void:

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

That seems to give the compiler all it needs without any bridge cast.

Upvotes: 2

architectpianist
architectpianist

Reputation: 2552

The reason you're getting the error is because you're comparing a string and a pointer to a string, when you really just want to compare two strings. When you're comparing two strings, you should use isEqualToString. So your code might look like this:

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

Hope this helps!

Upvotes: -1

Martin R
Martin R

Reputation: 539815

I can't tell you exactly why, but you don't get a warning or error if you swap the order of the comparison:

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

Upvotes: 2

Related Questions