0

I have a simple app: A text box bound to item.title. This property is exposed as a NSString, but internally is a NSMutableString.

The problem: Changes to the title property are not reflected in the UI.

Here is the implementation of item:

@interface Item : NSObject
{
    NSMutableString *_title;
}

@property NSString *title;

@end

And the implementation:

@implementation Item

-(void)mutateTitle
{
    [self willChangeValueForKey:@"title"];
    [_title appendString:@"mutated"];// this does not work
    //_title = [[NSMutableString alloc] initWithString:@"new instance"];// this works
    [self didChangeValueForKey:@"title"];
}

-(NSString *)title
{
    NSLog(@"get title returning: %@", _title);
    return _title;
}
-(void)setTitle:(NSString *)title
{
    _title = [[NSMutableString alloc] initWithString:title];
}

@end

When a button is pressed, we send mutateTitle to the item, which changes the title, and notifies KVO of the property change.

The UI does respond to the change, and when title is called, we return the correct string.

But the UI does not reflect the changes.

Note that if I un-comment the line where I assign a new instance to _title, the update happens fine.

Also, if title returns a copy of _title, it also works fine.

Why is this happening? Is there a way I can make this work as I want?


*edit: title is being assigned elsewhere in the code; it is not nil.

tenfour
  • 36,141
  • 15
  • 83
  • 142

1 Answers1

1

That's because if the mutable string mutates, but the property doesn't change (the pointer still points to the same object), then KVC will not consider it a real change. That is probably done for efficiency reasons (in case that didChangeValueForKey: is called but the string is the same, there's no need to update the UI).

I suggest to don't use a mutable string at all, it doesn't fit to your purpose. Just use a normal string, and instead of mutating it reassign it:

-(void)mutateTitle
{
    [self willChangeValueForKey:@"title"];
    _title= [_title stringByAppendingString: @"mutated"];
    [self didChangeValueForKey:@"title"];
} 
Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187