What does “% is unavailable: Use truncatingRemainder instead” mean?

余生颓废 提交于 2019-11-28 16:17:15

CMTimeGetSeconds() returns a floating point number (Float64 aka Double). In Swift 2 you could compute the remainder of a floating point division as

let rem = 2.5 % 1.1
print(rem) // 0.3

In Swift 3 this is done with

let rem = 2.5.truncatingRemainder(dividingBy: 1.1)
print(rem) // 0.3

Applied to your code:

let totalSeconds = CMTimeGetSeconds(self)
let hours = Int(totalSeconds / 3600)
let minutes = Int((totalSeconds.truncatingRemainder(dividingBy: 3600)) / 60)
let seconds = Int(totalSeconds.truncatingRemainder(dividingBy: 60))

However, in this particular case it is easier to convert the duration to an integer in the first place:

let totalSeconds = Int(CMTimeGetSeconds(self)) // Truncate to integer
// Or:
let totalSeconds = lrint(CMTimeGetSeconds(self)) // Round to nearest integer

Then the next lines simplify to

let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60

The % modulus operator is defined only for integer types. For floating-point types, you need to be more specific about the kind of IEEE 754 division/remainder behavior you want, so you have to call a method: either remainder or truncatingRemainder. (If you're doing floating-point math you actually need to care about this, and lots of other stuff, or you can get unexpected / bad results.)

If you actually intend to do integer modulus, you need to convert the return value of CMTimeGetSeconds to an integer before using %. (Note that if you do, you'll lop off the fractional seconds... depending on where you're using CMTime that may be important. Do you want minutes:seconds:frames, for example?)

Depending on how you want to present CMTime values in your UI, it might be better to extract the seconds value and pass it to NSDateFormatter or NSDateComponentsFormatter so you get appropriate locale support.

Bring back the simple modulo syntax in swift 3:

This syntax was actually suggested on Apples official swift mailing list here but for some reason they opted for a less elegant syntax.

infix operator %%/*<--infix operator is required for custom infix char combos*/
/**
 * Brings back simple modulo syntax (was removed in swift 3)
 * Calculates the remainder of expression1 divided by expression2
 * The sign of the modulo result matches the sign of the dividend (the first number). For example, -4 % 3 and -4 % -3 both evaluate to -1
 * EXAMPLE: 
 * print(12 %% 5)    // 2
 * print(4.3 %% 2.1) // 0.0999999999999996
 * print(4 %% 4)     // 0
 * NOTE: The first print returns 2, rather than 12/5 or 2.4, because the modulo (%) operator returns only the remainder. The second trace returns 0.0999999999999996 instead of the expected 0.1 because of the limitations of floating-point accuracy in binary computing.
 * NOTE: Int's can still use single %
 * NOTE: there is also .remainder which supports returning negatives as oppose to truncatingRemainder (aka the old %) which returns only positive.
 */
public func %% (left:CGFloat, right:CGFloat) -> CGFloat {
    return left.truncatingRemainder(dividingBy: right)
}

This simple swift 3 migration tip is part of a more comprehensive swift 3 migration guide with many insights (35k loc / 8-days of migration) http://eon.codes/blog/2017/01/12/swift-3-migration/

I found that the following works in Swift 3:

    let minutes = Int(floor(totalSeconds / 60))
    let seconds = Int(totalSeconds) % 60

where totalSeconds is a TimeInterval (Double).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!