Monday, January 9, 2017

How to use Swift's 'Data' structure to carry different types of data



Introduction


Swift provides the Data structure as an easy way to deal with byte buffers (sometimes called byte arrays). this means it holds raw bytes. This allows for very fast transfer of data (like over bluetooth).

It may be a little tricky to use it with some data types. This post provides ways to use Data to hold some of the most useful data types.

Just keep in mind that there has to be some kind of an "agreement" between your code and the consuming party of this data (it should know what data type and size are being sent).

If you are using a Swift playground, just import CoreData before you begin.

Code


UInt8 (and maybe booleans)

This is the primitive byte type as mentioned in the Swift docs; it is a raw byte after all 😅. It is the most straightforward to use as well.

Data can be used to hold an array of UInt8s directly.

let data = Data([1, 5])

/* or maybe create a flag,
 * change it in different places of the app
 * and send it like so..
 */
var flag: UInt8 = 0
let data = Data([flag])

This can also be used as a boolean flag by using 0 and 1 as values for a single element array (like you've seen in the above example).

String

Strings are also pretty easy to deal with.

let myString = "Cats are awesome"
let data = string.data(using: .utf8)

Just note that depending on your encoding of choice, the size is defferent. For this example with utf8, every character is 1 byte.

Float, Double and other number types

Other number types can take advantage of the flexibility of the UnsafeRawPointer to point directly to the memory location of the variable holding the data you want to send. This pointer is then used to initialize the Data object.

var myDouble = -9.52

let data = withUnsafePointer(to: &myDouble) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: myDouble))
}

This creates a Data object with the first parameter being a pointer to the myDouble variable.

The $0 is Swift's shorthand name of the UnsafePointer of myDouble. Check this answer if you need more info.

The second argument is the length which the Data initializer needs to walk through the memory to represent your variable, for this we have used the MemoryLayout.size(ofValue:) function to get the size of the myDouble variable automatically (which we know is 8 bytes, or 64 bits).

So this basically says: Starting at the position of myDouble in memory, walk 8 bytes, copy these bytes into a Data object.

Multiple data types with the same Data object


Most of the time, you would be okay with sending one type of data, but you might want to take advantage of the fact that you can send like double the size of the data you are sending at the moment to include other data.

Lets imagine that we want to send the price of a cat, along with a flag indicating if it is a kitten or a grown up cat.

// Like before, define a variable for the price
// and create a Data object with it
var price = 100.99

var data = withUnsafePointer(to: &price) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: price))
}
// now, define the kitten flag
var kitten: UInt8 = 1

// Make a Data object with it
let kittenFlagData = Data([kitten])

// append the two objects
data.append(kittenFlagData)

data now has 9 bytes, 8 bytes for the price (which, from the prespective of the consuming party, starts at offset 0).

It also has 1 byte for the flag (which, from the prespective of the consuming party, starts at offset 8).


That's it. Feel free to provide any kind of feedback.

Tuesday, January 3, 2017

I have created a web game that can be controlled with an iPhone. here's what it was like


The story

A couple of weeks ago, I have managed to create a web game that is totally controlled with iPhone over bluetooth.

The project is composed of the web game itself and a companion iPhone app to be used as the controller.

You use your phones sensors to move the character and two buttons for game actions are drawn on the controller app for interaction with the game world, your score vibrates when you're hit by an enemy and stores your best score (on the phone, for better mobility).

This post is for documenting the incident :D


some details

  • The game is written to use just web standards (although web bluetooth is not yet a standard, but it's built into the latest Chrome). no external libraries have been used, except for Rollup just to bundle the files (no transpiling).

  • The game is inside a canvas (obviously), no game frameworks were used.

  • Web Bluetooth API is still an experimental subset inside Chrome at the time of writing this project.


Lessons learned

  • The web is turning into a beast, I feel sorry for those who don't code for the web, they're missing a whole lot of excitement and fun times.

  • New Web APIs are very well thought and developer-friendly. I haven't dealt with bluetooth ever before and yet I have managed to make that game with so much less hair pulling than I was expecting.

  • Your fights with the Garbage Collector are gonna be aggressive. at first, you can see things disappear, then you try to capture that moment but you can't cuz it fires at random times, then you'll fire it up manually and say some bad words because it is eating up a global variable, at the end you'll read the API specification and understand what's going on. These fights are nasty, don't give up.

  • Trigonometry and Geometry are fun, after someone points out that you need to use a function that you haven't been taught in school to do what you want :D

  • Drawing your own assets is much more fun than searching for hours for the perfect asset for your game.

  • Drawing and animations on the raw canvas are not as scary as they seem, go for it, you don't need a full gaming framework if you're gonna make a small-to-medium project.

  • Byte buffers may be a little tricky to get your head around at first, but once you know them, you appreciate how minimal and powerful they are. (I may make another post about that one).

  • Apple has made a very good job with providing sensor readings, but they don't provide a precise straight forward way to get tilting angles, so you should come up with your own ticks for that matter.

  • Apple's Developer membership fee is pretty high, make sure to check it out :D

That said, the result was very satisfactory, it was smooth and responsive.

I'm going to record a video of the project in action soon and show it here to give you a better idea of what it does.

Update: here it is. I know it's super boring but it should deliver..