Skip to content

Instantly share code, notes, and snippets.

@Tron5000
Last active January 7, 2020 07:45
Show Gist options
  • Save Tron5000/7bb51318db1da86a3a78 to your computer and use it in GitHub Desktop.
Save Tron5000/7bb51318db1da86a3a78 to your computer and use it in GitHub Desktop.
Compressing/Decompressing UUID to 22 characters via base64
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)
@hansott
Copy link

hansott commented Dec 3, 2014

Thank you for this great piece of information! I used this to set my app UUID for a companion application for pebble smartwatch.

@Tron5000
Copy link
Author

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

@roop
Copy link

roop commented Oct 20, 2015

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.

@RaviDesai
Copy link

@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)
    }

@Tron5000
Copy link
Author

Good catch - thanks! I've updated the playground for Xcode 7.2.

@Tron5000
Copy link
Author

Tron5000 commented Oct 7, 2016

I've updated again for Swift 3 and Xcode 8.

@Tron5000
Copy link
Author

Tron5000 commented Jul 3, 2019

I've updated for Swift 5 and Xcode 10.2.1.

@zaifz
Copy link

zaifz commented Jan 7, 2020

Is there a way to avoid special characters?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment