Should conditional compilation be used to cope with difference in CGFloat on different architectures?

前端 未结 3 1617
南方客
南方客 2020-12-02 02:34

In answering this earlier question about getting a use of ceil() on a CGFloat to compile for all architectures, I suggested a solution along these lines:

<
相关标签:
3条回答
  • 2020-12-02 02:38
        var f : CGFloat = 0.5
        var result : CGFloat
        result = CGFloat(ceil(Double(f)))
    

    Tell me what I'm missing, but that seems pretty simple to me.

    0 讨论(0)
  • 2020-12-02 02:56

    Note that with current version of Swift the solution below is already implemented in the standard library and all mathematical functions are properly overloaded for Double, Float and CGFloat.

    Ceil is an arithmetic operation and in the same way as any other arithmetic operation, there should be an overloaded version for both Double and Float.

    var f1: Float = 1.0
    var f2: Float = 2.0
    
    var d1: Double = 1.0
    var d2: Double = 2.0
    
    var f = f1 + f2
    var d = d1 + d2
    

    This works because + is overloaded and works for both types.

    Unfortunately, by pulling the math functions from the C library which doesn't support function overloading, we are left with two functions instead of one - ceil and ceilf.

    I think the best solution is to overload ceil for Float types:

    func ceil(f: CFloat) -> CFloat {
        return ceilf(f)
    }
    

    Allowing us to do:

    var f: Float = 0.5
    var d: Double = 0.5
    
    var f: Float = ceil(f)
    var d: Double = ceil(d)
    

    Once we have the same operations defined for both Float and Double, even CGFloat handling will be much simpler.

    To answer the comment:

    Depending on target processor architecture, CGFloat can be defined either as Float or a Double. That means we should use ceil or ceilf depending on target architecture.

    var cgFloat: CGFloat = 1.5
    
    //on 64bit it's a Double
    var rounded: CGFloat = ceil(cgFloat)
    
    //on 32bit it's a Float
    var rounded: CGFloat = ceilf(cgFloat)
    

    However, we would have to use the ugly #if.

    Another option is to use clever casts

    var cgFloat: CGFloat = 1.5
    var rounded: CGFloat = CGFloat(ceil(Double(cgFloat))
    

    (casting first to Double, then casting the result to CGFloat)

    However, when we are working with numbers, we want math functions to be transparent.

    var cgFloat1: CGFloat = 1.5
    var cgFloat2: CGFloat = 2.5
    
    // this works on both 32 and 64bit architectures!
    var sum: CGFloat = cgFloat1 + cgFloat 2
    

    If we overload ceil for Float as shown above, we are able to do

    var cgFloat: CGFloat = 1.5
    
    // this works on both 32 and 64bit architectures!
    var rounded: CGFloat = ceil(cgFloat)
    
    0 讨论(0)
  • 2020-12-02 03:01

    Matt,

    Building on your solution, and if you use it in several places, then a little extension might make it more palatable:

    extension CGFloat {
        var ceil: CGFloat {
            #if arch(x86_64) || arch(arm64)
                return ceil(x)
            #else
                return ceilf(x)
            #endif
        }
    }
    

    The rest of the code will be cleaner:

    var x = CGFloat(0.5)
    x.ceil
    
    0 讨论(0)
提交回复
热议问题