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) {
|
if (project.target instanceof KonanTarget.IOS_X64) {
|
||||||
UtilsKt.codesign(project, "$buildDir/libobjcsmoke.dylib")
|
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 {
|
func testStringConversion() throws {
|
||||||
let test = TestStringConversion()
|
func test1() throws {
|
||||||
|
let test = TestStringConversion()
|
||||||
|
|
||||||
let buffer = NSMutableString()
|
let buffer = NSMutableString()
|
||||||
buffer.append("a")
|
buffer.append("a")
|
||||||
test.str = buffer
|
test.str = buffer
|
||||||
buffer.append("b")
|
buffer.append("b")
|
||||||
|
|
||||||
try assertEquals(actual: buffer, expected: "ab")
|
try assertEquals(actual: buffer, expected: "ab")
|
||||||
// Ensure test.str isn't affected by buffer mutation:
|
// Ensure test.str isn't affected by buffer mutation:
|
||||||
try assertEquals(actual: test.str as! NSString, expected: "a")
|
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 --------
|
// -------- 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
|
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 \
|
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
|
@interface TestAllocNoRetain : NSObject
|
||||||
@property BOOL ok;
|
@property BOOL ok;
|
||||||
@end;
|
@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()
|
testAllocNoRetain()
|
||||||
testNSOutputStreamToMemoryConstructor()
|
testNSOutputStreamToMemoryConstructor()
|
||||||
testExportObjCClass()
|
testExportObjCClass()
|
||||||
|
testCustomString()
|
||||||
|
testLocalizedStrings()
|
||||||
|
|
||||||
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
||||||
|
|
||||||
@@ -457,6 +459,28 @@ fun testExportObjCClass() {
|
|||||||
xor (TestExportObjCClass4().objCClassName == TestExportObjCClass34Name))
|
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
|
private val Any.objCClassName: String
|
||||||
get() = object_getClassName(this)!!.toKString()
|
get() = object_getClassName(this)!!.toKString()
|
||||||
|
|
||||||
|
|||||||
@@ -289,3 +289,34 @@ static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@end;
|
@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
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
#import <CoreFoundation/CFString.h>
|
||||||
#import <Foundation/NSException.h>
|
#import <Foundation/NSException.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#import "Memory.h"
|
#import "Memory.h"
|
||||||
@@ -69,12 +70,16 @@ OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str) {
|
|||||||
RETURN_OBJ(nullptr);
|
RETURN_OBJ(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t length = [str length];
|
CFStringRef immutableCopyOrSameStr = CFStringCreateCopy(nullptr, (CFStringRef)str);
|
||||||
NSRange range = {0, length};
|
|
||||||
|
auto length = CFStringGetLength(immutableCopyOrSameStr);
|
||||||
|
CFRange range = {0, length};
|
||||||
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
|
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
|
||||||
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
|
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());
|
RETURN_OBJ(result->obj());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user