github.com/michael-yuji/YSMessagePack

A pure Swift MessagePack implementation msgpack.org[Swift]


License
BSD-2-Clause

Documentation

YSMessagePack- for swift 3

YSMessagePack is a messagePack packer/unpacker written in swift (swift 3 ready). It is designed to be easy to use. YSMessagePack include following features:

  • Pack custom structs and classes / unpack objects by groups and apply handler to each group (easier to re-construct your struct$)
  • Asynchronous unpacking
  • Pack and unpack multiple message-packed data regardless of types with only one line of code
  • Specify how many items to unpack
  • Get remaining bytes that were not message-packed ; start packing from some index -- so you can mix messagepack with other protocol!!!
  • Helper methods to cast NSData to desired types
  • Operator +^ and +^= to join NSData

Version

1.6.2 (Dropped swift 2 support, swift 3 support only from now on)

Installation

  • Simply add files under YSMessagePack/Classes to your project,
  • use cocoapod, add "pod 'YSMessagePack', '~> 1.6.2' to your podfile

Usage

Pack:

let exampleInt: Int = 1
let exampleStr: String = "Hello World"
let exampleArray: [Int] = [1, 2, 3, 4, 5, 6]
let bool: Bool = true

// To pack items, just put all of them in a single array
// and call the `pack(items:)` function

//this will be the packed data
let msgPackedBytes: NSData = pack(items: [true, foo, exampleInt, exampleStr, exampleArray]) 

// Now your payload is ready to send!!!

But what if we have some custom data structure to send?

//To make your struct / class packable
struct MyStruct: Packable {  //Confirm to this protocol
    var name: String
    var index: Int
    func packFormat() -> [Packable] { //protocol function
        return [name, index] //pack order
    }

    func msgtype() -> MsgPackTypes {
        return .Custom
    }
}

let exampleInt: Int = 1
let exampleStr: String = "Hello World"
let exampleArray: [Int] = [1, 2, 3, 4, 5]
let bool: Bool = true

let foo = MyStruct(name: "foo", index: 626)

let msgPackedBytes = pack(items: [bool, foo, exampleInt, exampleStr, exampleArray])

Or you can pack them individually and add them to a byte array manually (Which is also less expensive)

let exampleInt: Int = 1
let exampleStr: String = "Hello World"
let exampleArray: [Int] = [1, 2, 3, 4, 5, 6]

//Now pack them individually
let packedInt = exampleInt.packed()

//if you didn't specific encoding, the default encoding will be ASCII
#if swift(>=3)
let packedStr = exampleStr.packed(withEncoding: NSASCIIStringEncoding) 
#else
let packedStr = exampleStr.packed(withEncoding: .ascii)
#endif
let packedArray = exampleArray.packed()
//You can use this operator +^ the join the data on rhs to the end of data on lhs
let msgPackedBytes: NSData = packedInt +^ packedStr +^ packedArray

Unpack

YSMessagePack offer a number of different ways and options to unpack include unpack asynchronously, see the example project for detail.

To unpack a messagepacked bytearray is pretty easy:

do {
    //The unpack method will return an array of NSData which each element is an unpacked object
    let unpackedItems = try msgPackedBytes.itemsUnpacked()
    //instead of casting the NSData to the type you want, you can call these `.castTo..` methods to do the job for you
    let int: Int = unpackedItems[2].castToInt()

    //Same as packing, you can also specify the encoding you want to use, default is ASCII
    let str: String = unpackedItem[3].castToString() 
    let array: NSArray = unpackedItems[4].castToArray() 
} catch let error as NSError{
    NSLog("Error occurs during unpacking: %@", error)
}

//Remember how to pack your struct? Here is a better way to unpack a stream of bytes formatted in specific format
 let testObj1 = MyStruct(name: "TestObject1", index: 1)
 let testObj2 = MyStruct(name: "TestObject2", index: 2)
 let testObj3 = MyStruct(name: "TestObject3", index: 3)

 let packed = packCustomObjects(testObj1, testObj2, testObj3) //This is an other method that can pack your own struct easier

 let nobjsInOneGroup = 2

 try! packed.unpackByGroupsWith(nobjsInOneGroup) {
     (unpackedData, isLast) -> Bool

     //you can also involve additional args like number of groups to unpack
     guard let name = unpackedData[0].castToString() else {return false} //abort unpacking hen something wrong
     let index = unpackedData[1]
     let testObj = MyStruct(name: name, index: index) // assembly      
     return true //proceed unpacking, or return false to abort
 } 

If you don't want to unpack every single thing included in the message-pack byte array, you can also specify an amount to unpack, if you want to keep the remaining bytes, you can put true in the returnRemainingBytes argument, the remaining bytes will stored in the end of the NSData array.

do {
    //Unpack only 2 objects, and we are not interested in remaining bytes
    let unpackedItems = try msgPackedBytes.itemsUnpacked(specific_amount: 2, returnRemainingBytes: false)
    print(unpackedItems.count) //will print 2
} catch let error as NSError{
    NSLog("Error occurs during unpacking: %@", error)
}