Andrey Morozov Andrey Morozov - 7 months ago 85
Swift Question

Why doesn't cast work from NSData to String? Swift

I have that code

func SendRequest(request: String) -> String
{
var response = ""
var (success, errmsg) = client.connect(timeout: 1)
if success
{
var (success, errmsg) = client.send(str: request + "\n" )
if success
{
while(true)
{
var data = client.read(10240*10)
if (data == nil)
{
break
}
var bytes = NSData.init(bytes: data!, length: data!.count)
var str = String.init(data: bytes, encoding: NSUTF8StringEncoding)
if str != nil{
response += str!
}
}
}
else
{
print(errmsg)
}
}
else
{
print(errmsg)
}
return response
}


Sometimes, cast
NSData
to
String
doesn't work. When I
print(str)
I see
nil
. Why is this happening? I use SwiftSocket library from GitHub. Sorry for my English.

This happening when my server send big
JSON
string. For example - if i received one object of message (my class) - everything always works. But if i received 4,5,6,... objects of message(my class) - this is working sometimes. MAGIC :(

New version of code

func SendRequest(request: String) -> String
{
var response = ""
var bigData: [UInt8] = []
var (success, errmsg) = client.connect(timeout: 1)
if success
{
var (success, errmsg) = client.send(str: request + "\n" )
if success
{
while(true)
{
var data = client.read(1024*10)
if (data == nil)
{
break

}
bigData.appendContentsOf(data!)
}
}
else
{
print(errmsg)
}
}
else
{
print(errmsg)
}
var bytes = NSData.init(bytes: bigData, length: bigData.count)

if let str = String(data: bytes, encoding: NSUTF8StringEncoding) as String? {
print(str)
response = str
}
return response
}

Answer

Note: I don't speak Swift. This following code may not compile, but it should give you the main idea/logic behind it.

The issue was because there NSData was incomplete (you receive them piece by piece and the buffer size may not be sufficient to handle the complete response at once), assuming that the bytes are really transformable to NSString according to the encoding used, as @zaph pointed out. Simple example: Transform a UIImage into NSData using UIImageJPEGRepresentation() for example, and try to transform it into NSString using the wanted encoding, it may not be valid, or do the same with the stream of a video.

An example for our case:
Full valid "Character": "1001", nothing with "10" nor "01".
You receive "10" only. And if you convert it to NSString, it's nil because it's not valid.
Then, you receive "01". And if you convert it to NSString, it's nil because it's not valid.
So you have to read all the NSData before transforming it to NSString.

So at the beginning, you can create a var finalData = NSMutableData.init() Then, each time you read the buffer, do:

var partialData = NSData.init(bytes: data, length: data.count)
finalData.appendData(partialData)

At the end, just transform finalData to String:

if let str = String(data:finalData, encoding: NSUTF8StringEncoding) {
    response = str
}
Comments