So in Swift 3, I had this function to convert a String representing Hexa data to Data type:
extension String {
public func fromHexStringtoData() -> Data? {
func convertToUInt8(u: UInt16) -> UInt8? {
switch(u) {
case 0x30 ... 0x39:
return UInt8(u - 0x30)
case 0x41 ... 0x46:
return UInt8(u - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(u - 0x61 + 10)
default:
return nil
}
}
let utf16 = self.utf16
guard let data = NSMutableData(capacity: utf16.count/2) else { return nil }
var i = utf16.startIndex
while i != utf16.endIndex {
guard let hi = convertToUInt8(u: utf16[i]) else { return nil }
//Need to convert following line to Swift 4
guard let lo = convertToUInt8(u: utf16[i.advanced(by: 1)]) else { return nil }
var value = hi << 4 + lo
data.append(&value, length: 1)
//Need to convert following line to Swift 4
i = i.advanced(by: 2)
}
return data as Data
}
}
How can I convert the advanced(by: n) in an optimal way?
You have to use like this :
extension String {
public func fromHexStringtoData() -> Data? {
func convertToUInt8(u: UInt16) -> UInt8? {
switch(u) {
case 0x30 ... 0x39:
return UInt8(u - 0x30)
case 0x41 ... 0x46:
return UInt8(u - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(u - 0x61 + 10)
default:
return nil
}
}
let utf16 = self.utf16
guard let data = NSMutableData(capacity: utf16.count/2) else { return nil }
var i = utf16.startIndex
while i != utf16.endIndex {
guard let hi = convertToUInt8(u: utf16[i]) else { return nil }
//changed to Swift 4
guard let lo = convertToUInt8(u: utf16[utf16.index(i, offsetBy: 1)]) else { return nil }
var value = hi << 4 + lo
data.append(&value, length: 1)
//changed to Swift 4
i = utf16.index(i, offsetBy: 2)
}
return data as Data
}
}
This is not a direct answer to your question, but your code scans the input string from start to end, one way. In such cases, you can re-write your code without using indices:
extension String {
public func fromHexStringToData() -> Data? {
func convertToUInt8(u: UInt16) -> UInt8? {
//...
}
var utf16Iterator = utf16.makeIterator()
var data = Data(capacity: utf16.count/2)
while let hiChar = utf16Iterator.next() {
guard
let hi = convertToUInt8(u: hiChar),
let loChar = utf16Iterator.next(),
let lo = convertToUInt8(u: loChar)
else { return nil }
let value = hi << 4 + lo
data.append(value)
}
return data
}
}
Works both in Swift 3 and Swift 4.
Related
I have the following code to decompress some Data back to a String in Swift 5. The method mostly works fine, but sometimes it fails with the following error message:
Thread 1: Fatal error: UnsafeMutablePointer.initialize overlapping range
extension Data
{
func decompress(destinationSize: Int) -> String?
{
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: destinationSize)
let decodedString = self.withUnsafeBytes
{
unsafeRawBufferPointer -> String? in
let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
if let unsafePointer = unsafeBufferPointer.baseAddress
{
let decompressedSize = compression_decode_buffer(destinationBuffer, destinationSize, unsafePointer, self.count, nil, COMPRESSION_ZLIB)
if decompressedSize == 0
{
return String.empty
}
let string = String(cString: destinationBuffer)
let substring = string.substring(0, decompressedSize)
return substring
}
return nil
}
return decodedString
}
}
The error occurs at the following line:
let string = String(cString: destinationBuffer)
Can someone please explain why this (sometimes) fails?
I have switched to the following code and now everything works fine (Swift 5):
import Compression
extension Data
{
func compress() -> Data?
{
return self.withUnsafeBytes
{
dataBytes in
let sourcePtr: UnsafePointer<UInt8> = dataBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
return self.perform(operation: COMPRESSION_STREAM_ENCODE, source: sourcePtr, sourceSize: self.count)
}
}
func decompress() -> Data?
{
return self.withUnsafeBytes
{
unsafeRawBufferPointer -> Data? in
let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
if let unsafePointer = unsafeBufferPointer.baseAddress
{
return self.perform(operation: COMPRESSION_STREAM_DECODE, source: unsafePointer, sourceSize: self.count)
}
return nil
}
}
fileprivate func perform(operation: compression_stream_operation, source: UnsafePointer<UInt8>, sourceSize: Int, preload: Data = Data()) -> Data?
{
guard sourceSize > 0 else { return nil }
let streamBase = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
defer { streamBase.deallocate() }
var stream = streamBase.pointee
let status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
guard status != COMPRESSION_STATUS_ERROR else { return nil }
defer { compression_stream_destroy(&stream) }
var result = preload
var flags: Int32 = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
let blockLimit = 64 * 1024
var bufferSize = Swift.max(sourceSize, 64)
if sourceSize > blockLimit
{
bufferSize = blockLimit
}
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }
stream.dst_ptr = buffer
stream.dst_size = bufferSize
stream.src_ptr = source
stream.src_size = sourceSize
while true
{
switch compression_stream_process(&stream, flags)
{
case COMPRESSION_STATUS_OK:
guard stream.dst_size == 0 else { return nil }
result.append(buffer, count: stream.dst_ptr - buffer)
stream.dst_ptr = buffer
stream.dst_size = bufferSize
if flags == 0 && stream.src_size == 0
{
flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
}
case COMPRESSION_STATUS_END:
result.append(buffer, count: stream.dst_ptr - buffer)
return result
default:
return nil
}
}
}
}
I want to generate random bytes using SecRandomCopyBytes in Swift 3.0. Here is how I did it in Swift 2.2
private static func generateRandomBytes() -> String? {
let data = NSMutableData(length: Int(32))
let result = SecRandomCopyBytes(kSecRandomDefault, 32, UnsafeMutablePointer<UInt8>(data!.mutableBytes))
if result == errSecSuccess {
return data!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
} else {
print("Problem generating random bytes")
return nil
}
}
In Swift 3, I tried to do it like this, since I know the concept of unsafemutablebytes is different now, but it doesn't allow me to return. If I comment out the return part, it still says Generic Parameter ResultType could not be inferred
fileprivate static func generateRandomBytes() -> String? {
var keyData = Data(count: 32)
_ = keyData.withUnsafeMutableBytes {mutableBytes in
let result = SecRandomCopyBytes(kSecRandomDefault, keyData.count, mutableBytes)
if result == errSecSuccess {
return keyData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
} else {
print("Problem generating random bytes")
return nil
}
}
return nil
}
Does anyone know how to fix this?
Thanks
You were close, but return inside the closure returns
from the closure, not from the outer function.
Therefore only SecRandomCopyBytes() should be called in the
closure, and the result passed back.
func generateRandomBytes() -> String? {
var keyData = Data(count: 32)
let result = keyData.withUnsafeMutableBytes {
(mutableBytes: UnsafeMutablePointer<UInt8>) -> Int32 in
SecRandomCopyBytes(kSecRandomDefault, 32, mutableBytes)
}
if result == errSecSuccess {
return keyData.base64EncodedString()
} else {
print("Problem generating random bytes")
return nil
}
}
For a "single-expression closure" the closure type can inferred
automatically, so this can be shortened to
func generateRandomBytes() -> String? {
var keyData = Data(count: 32)
let result = keyData.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, 32, $0)
}
if result == errSecSuccess {
return keyData.base64EncodedString()
} else {
print("Problem generating random bytes")
return nil
}
}
Swift 5 update:
func generateRandomBytes() -> String? {
var keyData = Data(count: 32)
let result = keyData.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, 32, $0.baseAddress!)
}
if result == errSecSuccess {
return keyData.base64EncodedString()
} else {
print("Problem generating random bytes")
return nil
}
}
This is the simplest and "Swiftiest" way to implement your function using Swift 5:
func generateRandomBytes() -> String? {
var bytes = [UInt8](repeating: 0, count: 32)
let result = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
guard result == errSecSuccess else {
print("Problem generating random bytes")
return nil
}
return Data(bytes).base64EncodedString()
}
Generally it is best practice in Swift to use guard statements as opposed to if/else statements when the control flow of a function depends on the success or failure of an expression or the presence of a non-nil value.
According to Apple Documentation it looks similar to this:
public func randomData(ofLength length: Int) throws -> Data {
var bytes = [UInt8](repeating: 0, count: length)
let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes)
if status == errSecSuccess {
return Data(bytes: bytes)
}
// throw an error
}
or as an additional initializer:
public extension Data {
public init(randomOfLength length: Int) throws {
var bytes = [UInt8](repeating: 0, count: length)
let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes)
if status == errSecSuccess {
self.init(bytes: bytes)
} else {
// throw an error
}
}
}
I have a UIView driven by two arrays: [Float] "data" and [UIColor] "colors". If the view isn't given proper data I am displaying an empty state, controlled by the guard statement you see here:
private func unwrap() -> ([Float], [UIColor]) {
guard
let data = data, !data.isEmpty,
let colors = colors, data.count == colors.count
else { return ([1], [UIColor.lightGray]) } // empty state
let total = data.reduce(0) { $0 + $1 }
if total == 0 { return ([1], [UIColor.lightGray]) }
return (data, colors)
}
I don't like the repetition of the empty state return ([1], [UIColor.lightGray]) being used twice. I've tried to add the data.reduce call inside the guard statement, something like:
private func unwrap() -> ([Float], [UIColor]) {
guard
let data = data, !data.isEmpty,
let colors = colors, data.count == colors.count,
data.reduce(0) { $0 + $1 } != 0
else { return ([1], [UIColor.lightGray]) } // empty state
return (data, colors)
}
...the compiler doesn't understand the syntax
private func unwrap() -> ([Float], [UIColor]) {
guard
let data = data, !data.isEmpty,
let colors = colors, data.count == colors.count,
let total = data.reduce(0) { $0 + $1 }, total != 0
else { return ([1], [UIColor.lightGray]) } // empty state
return (data, colors)
}
...the result of the closure data.reduce(0) { $0 + $1 } isn't optional so can't be included in the guard declaration.
Is there a cleaner way to do this?
This is my simplified version:
private func unwrap() -> ([Float], [UIColor]) {
guard let data = data, let colors = colors,
data.count == colors.count, data.reduce(0, +) != 0 else {
return ([1], [UIColor.lightGray])
} // empty state
return (data, colors)
}
Reduce can just use Float's + function, and a reduce on an empty data array will always be 0, so you don't need to check the empty status.
Figured it out.
private func unwrap() -> ([Float], [UIColor]) {
guard
let data = data, !data.isEmpty,
let colors = colors, data.count == colors.count,
(data.reduce(0) { $0 + $1 }) != 0
else { return ([1], [UIColor.lightGray]) } // empty state
return (data, colors)
}
How about making your return value a computed variable:
private func unwrap() -> ([Float], [UIColor]) {
var emptyVal: ([Float], [UIColor]) {
return ([1], [UIColor.lightGray])
}
guard
let data = data, !data.isEmpty,
let colors = colors, data.count == colors.count
else { return emptyVal } // empty state
let total = data.reduce(0) { $0 + $1 }
if total == 0 { return emptyVal }
return (data, colors)
}
I just realized that my old app is not working anymore because unsafeAddressOf is abandoned in Swift 3. I have been searching in Apple documentations and online tutorials but still cant figure out how to change my code to be compliant with Swift 3. Here is my code:
import UIKit
import ImageIO
extension UIImage {
public class func gifWithData(data: NSData) -> UIImage? {
guard let source = CGImageSourceCreateWithData(data, nil) else {
print("SwiftGif: Source for the image does not exist")
return nil
}
return UIImage.animatedImageWithSource(source: source)
}
public class func gifWithName(name: String) -> UIImage? {
guard let bundleURL = Bundle.main.url(forResource: name, withExtension: "gif") else {
print("SwiftGif: This image named \"\(name)\" does not exist")
return nil
}
guard let imageData = NSData(contentsOfURL: bundleURL) else {
print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
return nil
}
return gifWithData(imageData)
}
class func delayForImageAtIndex(index: Int, source: CGImageSource!) -> Double {
var delay = 0.1
// Get dictionaries
let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
let gifProperties: CFDictionary = unsafeBitCast(CFDictionaryGetValue(cfProperties, unsafeAddressOf(kCGImagePropertyGIFDictionary)), to: CFDictionary.self)
// Get delay time
var delayObject: AnyObject = unsafeBitCast(
CFDictionaryGetValue(gifProperties,
unsafeAddressOf(kCGImagePropertyGIFUnclampedDelayTime)),
to: AnyObject.self)
if delayObject.doubleValue == 0 {
delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties,
unsafeAddressOf(kCGImagePropertyGIFDelayTime)), to: AnyObject.self)
}
delay = delayObject as! Double
if delay < 0.1 {
delay = 0.1 // Make sure they're not too fast
}
return delay
}
class func gcdForPair( a: Int?, var _ b: Int?) -> Int {
// Check if one of them is nil
var a = a
if b == nil || a == nil {
if b != nil {
return b!
} else if a != nil {
return a!
} else {
return 0
}
}
// Swap for modulo
if a < b {
let c = a
a = b
b = c
}
// Get greatest common divisor
var rest: Int
while true {
rest = a! % b!
if rest == 0 {
return b! // Found it
} else {
a = b
b = rest
}
}
}
class func gcdForArray(array: Array<Int>) -> Int {
if array.isEmpty {
return 1
}
var gcd = array[0]
for val in array {
gcd = UIImage.gcdForPair(val, gcd)
}
return gcd
}
class func animatedImageWithSource(source: CGImageSource) -> UIImage? {
let count = CGImageSourceGetCount(source)
var images = [CGImage]()
var delays = [Int]()
// Fill arrays
for i in 0..<count {
// Add image
if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
images.append(image)
}
// At it's delay in cs
let delaySeconds = UIImage.delayForImageAtIndex(index: Int(i),
source: source)
delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
}
// Calculate full duration
let duration: Int = {
var sum = 0
for val: Int in delays {
sum += val
}
return sum
}()
// Get frames
let gcd = gcdForArray(array: delays)
var frames = [UIImage]()
var frame: UIImage
var frameCount: Int
for i in 0..<count {
frame = UIImage(CGImage: images[Int(i)])
frameCount = Int(delays[Int(i)] / gcd)
for _ in 0..<frameCount {
frames.append(frame)
}
}
// Heyhey
let animation = UIImage.animatedImage(with: frames,
duration: Double(duration) / 1000.0)
return animation
}
}
Does anyone have an idea how I can fix this code?
I want the function to generate random String without repeating.
For example this function maybe will print: ABCC
func randomString(length:Int) -> String {
let charSet = "ABCDEF"
var c = charSet.characters.map { String($0) }
var s:String = ""
for _ in (1...length) {
s.append(c[Int(arc4random()) % c.count])
}
return s
} print(randomString(length: 4))
and i want print random unique string only, E.g : ABCD
import GameplayKit
func randomString(length : Int) -> String {
let charSet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters)
let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: charSet) as! [Character]
let array = shuffled.prefix(length)
return String(array)
}
print(randomString(length: 4))
func randomString(length: Int) -> String {
let charSet = "ABCDEF"
var charSetArray = charSet.characters.map { String($0) }
var randArray: [String] = []
while charSetArray.count > 0 {
let i = Int(arc4random_uniform(UInt32(charSetArray.count)))
randArray.append(charSetArray[i])
charSetArray.remove(at: i)
}
var output: String = ""
for i in 0..<length {
output.append(randArray[i])
}
return output
}
How to use:
let randomString = "ABCDEF".random(length: 3)!
The return value is optional because the length might exceed the length of provided string.
Check out the full implementation:
import UIKit
import PlaygroundSupport
extension MutableCollection where Indices.Iterator.Element == Index {
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
swap(&self[firstUnshuffled], &self[i])
}
}
}
extension Sequence {
func shuffled() -> [Iterator.Element] {
var result = Array(self)
result.shuffle()
return result
}
}
extension String {
func random(length: Int) -> String? {
let uniqueCharacters = Array(Set(characters.map({ String($0) })))
guard length <= uniqueCharacters.count else { return nil }
guard length > 0 else { return nil }
return uniqueCharacters[0..<length].shuffled().joined()
}
}