Skip to content

Instantly share code, notes, and snippets.

@brennanMKE
Created September 25, 2019 17:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brennanMKE/d8b68a98aef9c38a3887aace98ecc206 to your computer and use it in GitHub Desktop.
Save brennanMKE/d8b68a98aef9c38a3887aace98ecc206 to your computer and use it in GitHub Desktop.
DeviceToken Swift Playground for transforming Data into a Hex String

Device Tokens and Push Notifications

When registering a device to push notifications a device token is provided in the form of Data. It is helpful to transform this stream of bytes into a string to use with HTTP requests and storing with UserDefaults in a human readable way. This DeviceToken type allows for creating an instance either is with data or a hex string and then accessing data and hex string properties. The Swift Playground also includes a series of unit tests which cover the DeviceToken type completely.

import Foundation
struct DeviceToken {
enum Failure: Error {
case invalidHexString
}
var data: Data
var hexString: String {
let result = data.map { String(format: "%02x", $0) }.joined().uppercased()
return result
}
init(data: Data) {
self.data = data
}
init(hexString: String) throws {
if hexString.count % 2 != 0 {
throw Failure.invalidHexString
}
let length = 2
let end = hexString.count/length
let range = 0..<end
let transformHex: (Int) -> String = {
String(hexString.dropFirst($0 * length).prefix(length))
}
let transformByte: (String) throws -> UInt8 = {
guard let value = UInt8($0, radix: 16) else {
throw Failure.invalidHexString
}
return value
}
let bytes = try range.map(transformHex).map(transformByte)
let data = Data(bytes)
self.data = data
}
}
/** TESTING **/
import XCTest
public class TestObserver: NSObject, XCTestObservation {
public static func observe() {
let observer = TestObserver()
XCTestObservationCenter.shared.addTestObserver(observer)
}
public func testCase(_ testCase: XCTestCase, didFailWithDescription description: String, inFile filePath: String?, atLine lineNumber: Int) {
print("🚫 \(description) line:\(lineNumber)")
}
public func testCaseDidFinish(_ testCase: XCTestCase) {
if testCase.testRun?.hasSucceeded == true {
print("✅ \(testCase)")
}
}
}
class DeviceTokenTests : XCTestCase {
func testEmptyHexString() {
guard let deviceToken = try? DeviceToken(hexString: "") else {
XCTFail()
return
}
XCTAssertEqual(deviceToken.hexString, "")
XCTAssertEqual(Array(deviceToken.data), [])
}
func testMaxHexString() {
guard let deviceToken = try? DeviceToken(hexString: "FF") else {
XCTFail()
return
}
XCTAssertEqual(deviceToken.hexString, "FF")
XCTAssertEqual(Array(deviceToken.data), [255])
}
func testVariousHexStringValues() {
guard let deviceToken = try? DeviceToken(hexString: "FF0110") else {
XCTFail()
return
}
XCTAssertEqual(deviceToken.hexString, "FF0110")
XCTAssertEqual(Array(deviceToken.data), [255, 1, 16])
}
func testEmptyData() {
let deviceToken = DeviceToken(data: Data([]))
XCTAssertEqual(deviceToken.hexString, "")
XCTAssertEqual(Array(deviceToken.data), [])
}
func testMaxData() {
let deviceToken = DeviceToken(data: Data([255]))
XCTAssertEqual(deviceToken.hexString, "FF")
XCTAssertEqual(Array(deviceToken.data), [255])
}
func testVariousDataValues() {
let deviceToken = DeviceToken(data: Data([255, 1, 16]))
XCTAssertEqual(deviceToken.hexString, "FF0110")
XCTAssertEqual(Array(deviceToken.data), [255, 1, 16])
}
func testInvalidHexStringValues() {
XCTAssertThrowsError(try DeviceToken(hexString: "FF1"))
XCTAssertThrowsError(try DeviceToken(hexString: "FF0g"))
}
}
TestObserver.observe()
DeviceTokenTests.defaultTestSuite.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment