import Foundation | |
// Compressing and decompressing a UUID to 22 characters via base64. | |
// Works great as a Swift playground. These articles were helpful: | |
// http://blog.codinghorror.com/equipping-our-ascii-armor/ | |
// http://69.195.124.60/~jasondoh/2013/08/14/creating-a-short-guid-in-objective-c/ | |
let identifier = NSUUID().uuidString | |
let base64TailBuffer = "=" | |
func compress(identifier: String) -> String? { | |
guard let tempUuid = NSUUID(uuidString: identifier) else { | |
return nil | |
} | |
var tempUuidBytes: UInt8 = 0 | |
tempUuid.getBytes(&tempUuidBytes) | |
let data = Data(bytes: &tempUuidBytes, count: 16) | |
let base64 = data.base64EncodedString(options: NSData.Base64EncodingOptions()) | |
return base64.replacingOccurrences(of: base64TailBuffer, with: "") | |
} | |
func rehydrate(shortenedIdentifier: String?) -> String? { | |
// Expand an identifier out of a CBAdvertisementDataLocalNameKey or service characteristic. | |
guard let shortenedIdentifier = shortenedIdentifier else { | |
return nil | |
} | |
// Rehydrate the shortenedIdentifier | |
let shortenedIdentifierWithDoubleEquals = shortenedIdentifier + base64TailBuffer + base64TailBuffer | |
let data = Data(base64Encoded: shortenedIdentifierWithDoubleEquals) | |
let uuidBytes = data?.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt8.self) } | |
let tempUuid = NSUUID(uuidBytes: uuidBytes) | |
return tempUuid.uuidString | |
} | |
let testCompress = compress(identifier: identifier) | |
let testRehydrate = rehydrate(shortenedIdentifier: testCompress) |
Glad this was helpful! I've updated the gist to accommodate the post-beta release of Swift.
Also, for anyone who is interested, I've written a blog post about this topic:
http://spinningtheweb.blogspot.com/2014/08/shortening-uuid-guid-in-swift.html
There's a memory corruption lurking here:
var tempUuidBytes: UInt8 = 0
tempUuid!.getUUIDBytes(&tempUuidBytes)
getUUIDBytes()
writes 16 bytes, while &tempUuidBytes
has allotted memory for just 1 byte.
@roop is right. This provided code crashes immediately for me in Xcode 7.1. Here's a modified version of the code that accepts nil and returns nil if something goes wrong (this met my use-case better).
func compressIdentifier(id: String?) -> String? {
let base64TailBuffer = "="
guard let identifier = id else {
return nil
}
guard let tempUuid = NSUUID(UUIDString: identifier) else {
return nil
}
var tempUuidBytes = [UInt8](count: 16, repeatedValue: 0)
tempUuid.getUUIDBytes(&tempUuidBytes)
let data = NSData(bytes: &tempUuidBytes, length: 16)
let base64 = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
return base64.stringByReplacingOccurrencesOfString(base64TailBuffer, withString: "", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
}
Good catch - thanks! I've updated the playground for Xcode 7.2.
I've updated again for Swift 3 and Xcode 8.
I've updated for Swift 5 and Xcode 10.2.1.
Is there a way to avoid special characters?
Thank you for this great piece of information! I used this to set my app UUID for a companion application for pebble smartwatch.