How can I convert data into types like Doubles, Ints and Strings in Swift?

后端 未结 1 1015
囚心锁ツ
囚心锁ツ 2020-12-03 11:57

I\'m working on building a custom file opener in iOS Swift for shapefiles (a GIS format, not particularly relevant to this question). These files have a header which is 100

相关标签:
1条回答
  • 2020-12-03 12:49

    Xcode 11 • Swift 5.1 or later

    To convert from String or any Numeric type to Data:

    extension StringProtocol {
        var data: Data { .init(utf8) }
    }
    

    extension Numeric {
        var data: Data {
            var source = self
            // This will return 1 byte for 8-bit, 2 bytes for 16-bit, 4 bytes for 32-bit and 8 bytes for 64-bit binary integers. For floating point types it will return 4 bytes for single-precision, 8 bytes for double-precision and 16 bytes for extended precision.
            return .init(bytes: &source, count: MemoryLayout<Self>.size)
        }
    }
    

    To convert from Data (bytes) back to String

    extension DataProtocol {
        var string: String? { String(bytes: self, encoding: .utf8) }
    }
    

    To convert from Data back to generic Numeric value

    extension Numeric {
        init<D: DataProtocol>(_ data: D) {
            var value: Self = .zero
            let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
            assert(size == MemoryLayout.size(ofValue: value))
            self = value
        }
    }
    

    extension DataProtocol {
        func value<N: Numeric>() -> N { .init(self) }
    }
    

    let value = 12.34                      // implicit Double 12.34
    let data = value.data                  // double data - 8 bytes
    let double = Double(data)              // implicit Double 12.34
    let double1: Double = .init(data)      // explicit Double 12.34
    let double2: Double = data.value()     // explicit Double 12.34
    let double3 = data.value() as Double   // casting to Double 12.34
    

    Now we can easily add a property for each Numeric type:

    extension DataProtocol {
        var integer: Int { value() }
        var int32: Int32 { value() }
        var float: Float { value() }
        var cgFloat: CGFloat { value() }
        var float80: Float80 { value() }
        var double: Double { value() }
        var decimal: Decimal { value() }
    }
    

    Playground testing

    let intData = 1_234_567_890_123_456_789.data    // 8 bytes (64 bit Integer)
    let dataToInt: Int = intData.integer                 // 1234567890123456789
    
    let intMinData = Int.min.data                   // 8 bytes (64 bit Integer)
    let backToIntMin = intMinData.integer           // -9223372036854775808
    
    let intMaxData = Int.max.data                   // 8 bytes (64 bit Integer)
    let backToIntMax = intMaxData.integer           // 9223372036854775807
    

    let myInt32Data = Int32(1_234_567_890).data     // 4 bytes (32 bit Integer)
    let backToInt32 = myInt32Data.int32             // 1234567890
    
    let int32MinData = Int32.min.data               // 4 bytes (32 bit Integer)
    let backToInt32Min = int32MinData.int32         // -2147483648
    
    let int32MaxData = Int32.max.data               // 4 bytes (32 bit Integer)
    let backToInt32Max = int32MaxData.int32         // 2147483647
    

    let myFloatData = Float.pi.data                 // 4 bytes (32 bit single=precison FloatingPoint)
    let backToFloat = myFloatData.float             // 3.141593
    backToFloat == .pi      // true
    
    let myCGFloatData = CGFloat.pi.data                 // 4 bytes (32 bit single=precison FloatingPoint)
    let backToCGFloat = myCGFloatData.cgFloat             // 3.141593
    backToCGFloat == .pi      // true
    
    let myDoubleData = Double.pi.data               // 8 bytes (64 bit double-precision FloatingPoint)
    let backToDouble = myDoubleData.double          // 3.141592653589793
    backToDouble == .pi     // true
    
    let myFloat80Data = Float80.pi.data             // 16 bytes (128 bit extended-precision FloatingPoint)
    let backToFloat80 = myFloat80Data.float80       // 3.141592653589793116
    backToFloat80 == .pi    // true
    
    let decimalData = Decimal.pi.data             // 20 bytes Decimal type
    let backToDecimal = decimalData.decimal       // 3.14159265358979323846264338327950288419
    backToDecimal == .pi    // true
    

    let stringBytes = "Hello World !!!".data.prefix(4)  // 4 bytes
    let backToString = stringBytes.string               //  "Hell"
    
    0 讨论(0)
提交回复
热议问题