Preserve original NSString in kotlin.String if possible
Thus fix localized strings in Kotlin.
This commit is contained in:
committed by
SvyatoslavScherbina
parent
57ada1c2cb
commit
ac74fb0a5a
@@ -3565,6 +3565,11 @@ interopTest("interop_objc_smoke") {
|
||||
if (project.target instanceof KonanTarget.IOS_X64) {
|
||||
UtilsKt.codesign(project, "$buildDir/libobjcsmoke.dylib")
|
||||
}
|
||||
|
||||
copy {
|
||||
from("interop/objc/Localizable.stringsdict")
|
||||
into("$testOutputLocal/$name/$target/en.lproj/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1078,16 +1078,41 @@ func testGH3525() throws {
|
||||
}
|
||||
|
||||
func testStringConversion() throws {
|
||||
let test = TestStringConversion()
|
||||
func test1() throws {
|
||||
let test = TestStringConversion()
|
||||
|
||||
let buffer = NSMutableString()
|
||||
buffer.append("a")
|
||||
test.str = buffer
|
||||
buffer.append("b")
|
||||
let buffer = NSMutableString()
|
||||
buffer.append("a")
|
||||
test.str = buffer
|
||||
buffer.append("b")
|
||||
|
||||
try assertEquals(actual: buffer, expected: "ab")
|
||||
// Ensure test.str isn't affected by buffer mutation:
|
||||
try assertEquals(actual: test.str as! NSString, expected: "a")
|
||||
try assertEquals(actual: buffer, expected: "ab")
|
||||
// Ensure test.str isn't affected by buffer mutation:
|
||||
try assertEquals(actual: test.str as! NSString, expected: "a")
|
||||
}
|
||||
|
||||
func ensureNoCopy(nsStr: NSString) throws {
|
||||
let test = TestStringConversion()
|
||||
|
||||
test.str = nsStr
|
||||
let nsStr2 = test.str as! NSString
|
||||
|
||||
// Ensure no additional NSString created on both conversions:
|
||||
try assertTrue(nsStr === nsStr2)
|
||||
}
|
||||
|
||||
func test2() throws {
|
||||
var str = "a"
|
||||
str += NSObject().description
|
||||
try ensureNoCopy(nsStr: str as NSString)
|
||||
|
||||
try ensureNoCopy(nsStr: NSString("abc"))
|
||||
|
||||
try ensureNoCopy(nsStr: NSString(format: "%d%d%d", 3, 2, 1))
|
||||
}
|
||||
|
||||
try test1()
|
||||
try test2()
|
||||
}
|
||||
|
||||
// -------- Execution of the test --------
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- AUTO-GENERATED FILE. DO NOT MODIFY. -->
|
||||
<!-- This file was automatically generated by the LocoLaser tool. -->
|
||||
<!-- It should not be modified by hand. -->
|
||||
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>screen_main_plural_string</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@value@</string>
|
||||
<key>value</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>other</key>
|
||||
<string>Plural: %d apples</string>
|
||||
<key>one</key>
|
||||
<string>Plural: one apple</string>
|
||||
<key>zero</key>
|
||||
<string>Plural: no apples</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,4 +1,4 @@
|
||||
language = Objective-C
|
||||
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h
|
||||
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h Foundation/NSBundle.h
|
||||
headerFilter = **/smoke.h Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h \
|
||||
objc/objc.h
|
||||
objc/objc.h Foundation/NSBundle.h
|
||||
|
||||
@@ -224,3 +224,18 @@ Protocol* getPrinterProtocol() {
|
||||
@interface TestAllocNoRetain : NSObject
|
||||
@property BOOL ok;
|
||||
@end;
|
||||
|
||||
@interface CustomString : NSString
|
||||
- (instancetype)initWithValue:(int)value;
|
||||
@property int value;
|
||||
@end;
|
||||
|
||||
CustomString* _Nonnull createCustomString(int value) {
|
||||
return [[CustomString alloc] initWithValue:value];
|
||||
}
|
||||
|
||||
int getCustomStringValue(CustomString* str) {
|
||||
return str.value;
|
||||
}
|
||||
|
||||
extern BOOL customStringDeallocated;
|
||||
|
||||
@@ -29,6 +29,8 @@ fun run() {
|
||||
testAllocNoRetain()
|
||||
testNSOutputStreamToMemoryConstructor()
|
||||
testExportObjCClass()
|
||||
testCustomString()
|
||||
testLocalizedStrings()
|
||||
|
||||
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
||||
|
||||
@@ -457,6 +459,28 @@ fun testExportObjCClass() {
|
||||
xor (TestExportObjCClass4().objCClassName == TestExportObjCClass34Name))
|
||||
}
|
||||
|
||||
fun testCustomString() {
|
||||
assertFalse(customStringDeallocated)
|
||||
|
||||
fun test() = autoreleasepool {
|
||||
val str: String = createCustomString(321)
|
||||
assertEquals("321", str)
|
||||
assertEquals("CustomString", str.objCClassName)
|
||||
assertEquals(321, getCustomStringValue(str))
|
||||
}
|
||||
|
||||
test()
|
||||
kotlin.native.internal.GC.collect()
|
||||
assertTrue(customStringDeallocated)
|
||||
}
|
||||
|
||||
fun testLocalizedStrings() {
|
||||
val key = "screen_main_plural_string"
|
||||
val localizedString = NSBundle.mainBundle.localizedStringForKey(key, value = "", table = "Localizable")
|
||||
val string = NSString.localizedStringWithFormat(localizedString, 5)
|
||||
assertEquals("Plural: 5 apples", string)
|
||||
}
|
||||
|
||||
private val Any.objCClassName: String
|
||||
get() = object_getClassName(this)!!.toKString()
|
||||
|
||||
|
||||
@@ -289,3 +289,34 @@ static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl;
|
||||
return self;
|
||||
}
|
||||
@end;
|
||||
|
||||
BOOL customStringDeallocated = NO;
|
||||
|
||||
@implementation CustomString {
|
||||
NSString* delegate;
|
||||
}
|
||||
|
||||
- (instancetype)initWithValue:(int)value {
|
||||
if (self = [super init]) {
|
||||
self->delegate = @(value).description;
|
||||
self.value = value;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unichar)characterAtIndex:(NSUInteger)index {
|
||||
return [self->delegate characterAtIndex:index];
|
||||
}
|
||||
|
||||
- (NSUInteger)length {
|
||||
return self->delegate.length;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
customStringDeallocated = YES;
|
||||
}
|
||||
@end;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#if KONAN_OBJC_INTEROP
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <CoreFoundation/CFString.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import "Memory.h"
|
||||
@@ -69,12 +70,16 @@ OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str) {
|
||||
RETURN_OBJ(nullptr);
|
||||
}
|
||||
|
||||
size_t length = [str length];
|
||||
NSRange range = {0, length};
|
||||
CFStringRef immutableCopyOrSameStr = CFStringCreateCopy(nullptr, (CFStringRef)str);
|
||||
|
||||
auto length = CFStringGetLength(immutableCopyOrSameStr);
|
||||
CFRange range = {0, length};
|
||||
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
|
||||
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
|
||||
|
||||
[str getCharacters:rawResult range:range];
|
||||
CFStringGetCharacters(immutableCopyOrSameStr, range, rawResult);
|
||||
|
||||
result->obj()->meta_object()->associatedObject_ = (void*)immutableCopyOrSameStr;
|
||||
|
||||
RETURN_OBJ(result->obj());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user