Подтвердить что ты не робот

Что означает "% недоступно: вместо этого используйте truncatingRemainder"?

Я получаю следующую ошибку при использовании кода для расширения, я не уверен, что они просят просто использовать другой оператор или изменить значения в выражении на основе поиска в Интернете.

Ошибка:% недоступно: вместо этого используйте truncatingRemainder

Код расширения:

extension CMTime {
    var durationText:String {
        let totalSeconds = CMTimeGetSeconds(self)
        let hours:Int = Int(totalSeconds / 3600)
        let minutes:Int = Int(totalSeconds % 3600 / 60)
        let seconds:Int = Int(totalSeconds % 60)

        if hours > 0 {
            return String(format: "%i:%02i:%02i", hours, minutes, seconds)
        } else {
            return String(format: "%02i:%02i", minutes, seconds)
        }
    }
}

Ошибка (и) возникает при настройке переменных минут и секунд.

4b9b3361

Ответ 1

CMTimeGetSeconds() возвращает число с плавающей запятой (Float64 aka Double). В Swift 2 вы можете вычислить остаток от деления с плавающей запятой как

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

В Swift 3 это делается с помощью

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

Применяется к вашему коду:

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

Однако в этом конкретном случае легче преобразовать продолжительность к целому числу в первую очередь:

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

Затем следующие строки упрощаются до

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

Ответ 2

Оператор модуля % определяется только для целых типов. Для типов с плавающей запятой вам нужно быть более конкретным в отношении поведения деления/останова IEEE 754, которое вы хотите, поэтому вы должны вызвать метод: remainder или truncatingRemainder. (Если вы делаете математику с плавающей запятой, вам действительно нужно заботиться об этом, а много других вещей, или вы можете получить неожиданные/плохие результаты.)

Если вы действительно намереваетесь выполнять целочисленный модуль, вам нужно преобразовать возвращаемое значение CMTimeGetSeconds в целое число перед использованием %. (Обратите внимание: если вы это сделаете, вы отбросите дробные секунды... в зависимости от того, где вы используете CMTime, что может быть важно. Вам нужны минуты: секунды: кадры, например?)

В зависимости от того, как вы хотите представить значения CMTime в пользовательском интерфейсе, лучше извлечь значение секунд и передать его NSDateFormatter или NSDateComponentsFormatter, чтобы получить соответствующую поддержку локали.

Ответ 3

Возвращает простой синтаксис по модулю в swift 3:

Этот синтаксис фактически был предложен в официальном списке быстрой рассылки Apples здесь, но по какой-то причине они выбрали менее элегантный синтаксис.

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

Этот простой совет быстрого перехода 3 является частью более подробного руководства по миграции с быстрой скоростью 3 с большим количеством сведений (35k loc/8-days of migration) http://stylekit.org/blog/2017/01/12/swift-3-migration/

Ответ 4

Я обнаружил, что в Swift 3 работает следующее:

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

где totalSeconds - TimeInterval (Double).