When setting UIBarButtonItem.title to an empty string that is a tagged pointer, it interprets it as nil instead of empty string

Originator:lewis
Number:rdar://22828505 Date Originated:23-Sep-2015
Status:Open Resolved:
Product:iOS SDK Product Version:9.0
Classification: Reproducible:
 
Summary:
An NSTaggedPointerString of an empty value can be created in some circumstances. When setting the title property of a UIBarButtonItem to it, it interprets it as nil. However, for other types of strings it behaves properly

Steps to Reproduce:
Create an XCTestCase that looks like this.

One test will fail. One won't.

//
//  TitleExampleTests.m
//  TitleExampleTests
//
//  Created by Mike Lewis on 9/23/15.
//  Copyright © 2015 Square, Inc. All rights reserved.
//

#import <XCTest/XCTest.h>
#import <objc/runtime.h>

static NSString *const EmptyString = @"";

@interface TitleExampleTests : XCTestCase

@property (nonatomic) UIViewController *viewController;

@end


@implementation TitleExampleTests

- (void)setUp {
    [super setUp];
    self.viewController = [[UIViewController alloc] init];
    self.viewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
}

// This case will fail.
- (void)testTaggedPointer {
    // It's a bit tricky to make a tagged pointer of an empty string, but this will do it.
    NSString *empty = [[[@"\"\"" mutableCopy] copy] substringWithRange:NSMakeRange(1, 0)];
    
    NSAssert([@"NSTaggedPointerString" isEqualToString:NSStringFromClass([empty class])], @"Expecting this to equal a tagged pointer string");
    XCTAssertEqualObjects(empty, @"");
    
    self.viewController.navigationItem.backBarButtonItem.title = empty;
    
    // This will fail in iOS 9
    XCTAssertNotNil(self.viewController.navigationItem.backBarButtonItem.title);
}

// This case will pass
- (void)testConstant {
    NSAssert(![@"NSTaggedPointerString" isEqualToString:NSStringFromClass(EmptyString.class)], @"Expecting this to not be a tagged pointer string");
    self.viewController.navigationItem.backBarButtonItem.title = EmptyString;
    XCTAssertNotNil(self.viewController.navigationItem.backBarButtonItem.title);
}

@end


Expected Results:
It should be empty string in both cases

Actual Results:
It isn't an empty string, but rather nil in the case of a tagged pointer.

Version:
xcode 7, iOS 9.0 simulator/device

Notes:
Not sure if the substringWithRange should ever return a tagged pointer of an empty string. It was actually very difficult reproducing a tagged empty string to be created.

Configuration:
When running tests, when in the playground. Whenever

Attachments:

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!