Is this right way to use NSString BytesNoCopy ?

In my project, i am initialising bytes with some character in cpp function, func CreateByteWithVal (), and passing to a function, func CreateNSStringFromCString(_ pPtr : UnsafeMutableRawPointer, _ pLength : Int), in swift using Swift-Cpp interop.

CreateByteWithVal () allocates bytes on heap with value "AAAAAAAAAA", also calls swift function CreateNSStringFromCString.

And func CreateNSStringFromCString (_ pPtr : UnsafeMutableRawPointer, _ pLength : Int) creates a NSString instance using NSString's BytesNoCopy initialiser using the bytes (pPtr) passed to it in parameter.

Cpp code:

void
CppClass::CreateByteWithVal ()
{
    char * bytesForString = (char *) malloc (10);
    
    
    memset (bytesForString, 65, 10);

    Interop_Swift::CreateNSStringFromCString (bytesForString, 10);
    
}

Swift code:

public func CreateNSStringFromCString (_ pPtr : UnsafeMutableRawPointer, _ pLength : Int) {
    
    let ns_string:NSString = NSString (bytesNoCopy: pPtr, length: pLength, encoding: String.Encoding.utf8.rawValue, freeWhenDone: false)

}

If we modify the byte values in memory from C++ directly, the NSString instance, which is supposed to be immutable by nature, reflects these changes. Is this approach appropriate, or is there something we're overlooking or need to address? In our project, we are mutating the byte values directly like this, and the changes are being reflected in the NSString instance :

memset (bytesForString, 66, 5);

Essentially, I want to confirm whether we can use this method to modify values through C++ without directly mutating the NSString instance.

For the UI, we'll be reading the NSString instance by creating a native Swift String instance from it, like this:

let str:String = ns_string as String

Will the value of str remain consistent as long as we ensure that the correct bytes are provided by C++?

Answered by DTS Engineer in 817586022

Yeah, what endecotp said.

In general, NSString values are meant to be immutable. If you create one using the no-copy API and then mutate the underlying byte buffer, bad things will happen. For example, the string value will change without the string hash changing, so folks who rely on the hash, like for an NSDictionary that uses the string as a key, will be horribly broken.

In addition, if you pass NO to freeWhenDone then you have to guarantee that the byte buffer outlives the string. That’s hard to do given Objective-C’s reference counting. The only reasonable approaches are to either use a static buffer or leak the buffer.

Don’t continue down this path.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Is this approach appropriate

No, it’s absolutely horrible.

Yeah, what endecotp said.

In general, NSString values are meant to be immutable. If you create one using the no-copy API and then mutate the underlying byte buffer, bad things will happen. For example, the string value will change without the string hash changing, so folks who rely on the hash, like for an NSDictionary that uses the string as a key, will be horribly broken.

In addition, if you pass NO to freeWhenDone then you have to guarantee that the byte buffer outlives the string. That’s hard to do given Objective-C’s reference counting. The only reasonable approaches are to either use a static buffer or leak the buffer.

Don’t continue down this path.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Is this right way to use NSString BytesNoCopy ?
 
 
Q