Swift. How to write bytes from NSData into another NSData? - ios

I'm trying to concatenate two NSData objects into one NSMutableData, and than get them back. For now i'm trying to do it in such way:
Get length of first object.
Write into NSMutableData in such order: first object length, first object, second object.
Code looks like:
let firstString = "first_string";
let secondString = "secondSting";
let firstData = firstString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let secondData = secondString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let mutableData = NSMutableData()
var length = firstData.length
mutableData.appendBytes(&length, length: sizeof(Int))
mutableData.appendData(firstData)
mutableData.appendData(secondData)
Then I want to get datas back. So I suppose to read first data length and then get two datas.
var length = 0
mutableData.getBytes(&length, length: sizeof(Int))
But when I'm trying to get data I'm getting crash instead:
var data = NSData()
mutableData.getBytes(&data, range: NSMakeRange(sizeof(Int), length))
Maybe somebody know where is my problem or how to get datas?

You can extract the data using subdataWithRange():
let firstData1 = mutableData.subdataWithRange(NSMakeRange(sizeof(Int), length))
if let firstString1 = NSString(data: firstData1, encoding: NSUTF8StringEncoding) as? String {
println(firstString1)
} else {
// bad encoding
}
Your solution
var data = NSData()
mutableData.getBytes(&data, range: NSMakeRange(sizeof(Int), length))
does not work and crashes because NSData is a reference type and
data a pointer to the object. You are overwriting this pointer
and the following bytes in memory.

This works perfectly without a crash in my storyboard. I just omitted the second var before length in order to avoid redefining it.
Here is the output for each line:
"first_string"
"secondSting"
<66697273 745f7374 72696e67> // let firstData = ...
<7365636f 6e645374 696e67> // let secondData = ...
<> // let mutableData = ...
12 // var length = ...
// appending data
<0c000000 00000000>
<0c000000 00000000 66697273 745f7374 72696e67>
<0c000000 00000000 66697273 745f7374 72696e67 7365636f 6e645374 696e67>
0 // length = 0
<0c000000 00000000 66697273 745f7374 72696e67 7365636f 6e645374 696e67>
12 // length
This means you probably have an error somewhere else. You did not redefine length, right?

Related

convert content of the characteristic in swift

I have a question about how I could do this instruction in swift?
NSData * data = characteristic.value;
Byte *resultByte = (Byte *)[data bytes];
I understand that the first line is like this, but how can I get the bytes
let data = characteristic.value! as NSData
You can create an array of bytes from the data simply with
if let data = characteristic.value {
let bytes = Array(data) // [UInt8]
}
But often you don't need to create an extra array because Data
is a collection and you can directly access the individual bytes via
subscripting:
if let data = characteristic.value {
let byte0 = data[0]
let byte1 = data[1]
// ...
}
or get a pointer to the raw bytes with
if let data = characteristic.value {
data.withUnsafeBytes { (bytePtr: UnsafePointer<UInt8>) in
// ...
}
}

Get input from UITextField(HEX) data and send out via bluetooth LE

i'm currently trying to get the data(HEX) from UITextfield, and i would want to store the data in UInt8 i'm currently doing this.
let incomingdata = UInt8(textfield.text!)
by doing this it returns nil. The purpose i'm doing this because after i gets the data from UITextField, i would send out the data in UInt8 format via bluetooth. Can someone suggest me how can i do that?Thank you
I update my question, in short i input 72AE in UITextField, i get the text in string format, but in the end i wan to convert it to UInt8 and it is in 0x72, 0xAE
In short, i'm converting HexString to UInt8
You can convert a hex value to an Int with this code.
let hex2int = String(format:"%2X", hex)
Quite easy.
I might be misunderstanding your question, but if you would like to covert string into array of Int, this is how you might go about it.
let stringFromTextField = "anything"
// Convert stringFromTextField to NSString and then then convert it to NSData
// in encoding of your choosing
if let data = NSString(string: stringFromTextField).dataUsingEncoding(NSUTF8StringEncoding) where data.length > 1 {
// Create buffer
var buffer: Int = 0
let bufferSize = 1
let adjustedDataLenght = data.length / bufferSize
var yourInt = [Int]()
// Loop over data and get bytes
for i in 0..<adjustedDataLenght {
data.getBytes(&buffer, range: NSRange(location: i, length: bufferSize))
yourInt.append(buffer)
}
// Here are your ints
print(yourInt)
}
Works in playground. Hope it helped.

Swift - how to count bytes and convert them to megabytes?

I try to add bytes with bytes in order to get space that will be occupied by photos which i retrieve from internet.
I have following code, it gets sizes in bytes for each id in array of id
var diskSpace:Int64 = 0
for var i = 0; i < array.count; i++ {
let id = array[i]
let urlString = "urlToFetchData"
if let url = NSURL(string: urlString) {
if let data = try? NSData(contentsOfURL: url, options: []) {
let json = JSON(data: data)
let size = Int64(json["size"].stringValue)
diskSpace = diskSpace + size!
}
}
}
var diskSpaceInMb = diskSpace / 1024 / 1024
print("diskSpaceInMb is \(diskSpaceInMb)")
for example, I try to get size of three elements, which have following size in bytes (these sizes in bytes I receive in json)
3223653
5855382
8948976
when the code above is executed i receive result of
diskSpaceInMb is 8
which is obviously not try
How to convert bytes to megabytes correctly ?
let fileSizeWithUnit = ByteCountFormatter.string(fromByteCount: diskSpace, countStyle: .file)
print("File Size: \(fileSizeWithUnit)")
The problem is obviously in the for loop. Maybe the JSON is not as you expect.
Another reason why this might fail is the you use the try? keyword, which in this context it means that it gives you a value if it succeeds, but otherwise it returns nil. In your case, it may silently fail. If you want to check if it fails, you could add an else branch.

Fatal error: unexpected found nil while unwrapping an optional values

whole code is like this:
var inputStream :NSInputStream?
var outputStream:NSOutputStream?
NSStream.getStreamsToHostWithName(ip, port: port, inputStream: &inputStream, outputStream: &outputStream)
let reader = inputStream
let writer = outputStream
writer?.open()
reader?.open()
var message : UInt8 = 0
while reader!.read(&message, maxLength: 1)>0
{
let wa = NSString(bytes: &message, length: 1, encoding: CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))) as! String
}
when the message i receive is a chinese character, the last line throws this:
fatal error:unexpected found nil while unwrapping an optional value, at the mean time, the value of message is 196
does anybody know how to solve this problem?
According to this page, if the byte you read is in the range 0x81-0xfe, the character is encoded using two or four bytes, so trying to decode just the first byte will fail. The NSString constructor will return nil, and attempting to unwrap it (with as! String) will throw that error.
You need to check what byte you read, and read another byte if necessary based on the first byte. Then you need to check the second byte, and possible read two more bytes. Finally, you need to pass all of the one, two, or four bytes to the NSString constructor in a single buffer.
Try to change message type for inputData like this for example:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue) {
let bufferSize = 1024
var message = Array<UInt8>(count:bufferSize, repeatedValue: 0)
while true {
let bytesRead = self.inputStream!.read(&message, maxLength: bufferSize)
let responseString = NSString(bytes: message, length: message.count, encoding: NSUTF8StringEncoding) as! String
// Do somthing with response
...
}
}

Can't figure out why I get a fatal error: unexpectedly found nil while unwrapping an Optional value

I keep getting this error :
fatal error: unexpectedly found nil while unwrapping an Optional value
and cannot figure out how to debug it!
Here's my code :
func readCSV() -> Array<String> {
// Creates a new array of strings
var csvArray : Array<String> = Array<String>()
if let url: NSURL = NSURL(string : "URLFROMCSV" ) {
// Creates an Input Stream that will load the datas from our URL
let data :NSData! = NSData(contentsOfURL: url)!
let stream : NSInputStream! = NSInputStream(data: data)
// Opens the receiving stream
stream.open()
// Sets a buffer with a given size size
let bufferSize = 1024
var buffer = Array <UInt8>(count: bufferSize, repeatedValue: 0)
// String variable initialization
var csvFullString : String = ""
// While the stream receives datas, parses datas, convert them into strings and then concatenate them into one big string
while (stream.hasBytesAvailable) {
let readSize = stream.read(&buffer, maxLength: bufferSize)
let csvRaw = NSString (bytes: &buffer, length: readSize, encoding: NSUTF8StringEncoding)
let csvString = csvRaw as String!
csvFullString = csvFullString + csvString
}
// Fills the array with each strings. Separation between strings is made when a Θ character is parsed
csvArray = csvFullString.componentsSeparatedByString("Θ")
// Delete each null string
for(var i = 0 ; i < csvArray.count; i++) {
if(csvArray[i] == "") {
csvArray.removeAtIndex(i)
}
}
}
return csvArray
}
After searching on the web, I'm pretty sure it has something to do with unwrapping elements but the fact is when I debug it, i don't get any nil value anywhere.
PS: Would like to upload a screen but can't because i don't have 10 reputation, so bad!
Thanks in advance!
EDIT : Line let data :NSData! = NSData(contentsOfURL: url)! got the error.
Terry
You're probably creating the error in one of these two lines (though it may show up later):
let data :NSData! = NSData(contentsOfURL: url)!
let stream : NSInputStream! = NSInputStream(data: data)
You're assigning an optional value to an implicitlyUnwrappedOptional type and then using it without checking if you have a valid value.
This is why if let exists. It's a little funny that you've started to indent as if you're using if let but aren't.
Try this instead:
if let url = NSURL(string : "http://gorillaapplications.com/etablissements.csv" ) {
// Creates an Input Stream that will load the datas from our URL
if let data = NSData(contentsOfURL: url) {
let stream = NSInputStream(data: data)
stream.open()
// rest of your code here
}
else {
println("Didn't get a data object")
}
}
else {
println("Didn't get a URL object")
}
You really need to grasp Optionals for Swift. I'd recommend reading my Optionals chapter in this iBook: https://itunes.apple.com/us/book/swift-optionals-generics-for/id943445214?mt=11&uo=4&at=11lMGu
Update:
Since you added a bit more in your comments above, you're saying you get the error on this line: let data: NSData! = NSData(contentsOfURL: url)!. This is because of the ! at the end, which tells Swift you're sure that this function will return a valid value, so just use it, without checking if it's nil first. In your case, the function is returning nil and so your app crashes. Using the sample code I've provided above, you'll see that you'll no longer get a crash, but your code will execute the "Didn't get a data object" line. You'll need to correctly handle the case where you can't load data from that URL.

Resources