web-dev-qa-db-fra.com

Que signifie "% est indisponible: utilisez plutôt truncatingRemainder"?

L'erreur suivante s'affiche lorsque j'utilise du code pour une extension. Je ne sais pas s'ils demandent simplement d'utiliser un autre opérateur ou de modifier les valeurs de l'expression en fonction d'une recherche Internet.

Erreur:% est indisponible: utilisez plutôt truncatingRemainder

Code d'extension:

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

La ou les erreurs se produisent lors de la définition des variables minutes et secondes.

87
Cosmic Arrows

CMTimeGetSeconds() renvoie un nombre à virgule flottante (Float64 aka Double). Dans Swift 2, vous pouvez calculer le reste d’une division en virgule flottante comme

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

Dans Swift 3, cela se fait avec

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

Appliqué à votre 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))

Cependant, dans ce cas particulier, il est plus facile de convertir la durée en un entier en premier lieu:

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

Ensuite, les lignes suivantes se simplifient pour

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

L'opérateur de module % est défini uniquement pour les types entiers. Pour les types à virgule flottante, vous devez préciser le type de comportement de division/reste IEEE 754 souhaité. Vous devez donc appeler une méthode: remainder ou truncatingRemainder =. (Si vous faites des calculs en virgule flottante, vous devez vraiment vous soucier de cela, et plein d'autres choses , ou vous pouvez obtenir des résultats inattendus/mauvais.)

Si vous avez réellement l'intention de faire un module entier, vous devez convertir la valeur de retour de CMTimeGetSeconds en entier avant d'utiliser %. (Notez que si vous le faites, vous réduirez la fraction de seconde ... en fonction de l'endroit où vous utilisez CMTime, cela peut être important. Voulez-vous des minutes: secondes: images, par exemple?)

Selon la manière dont vous souhaitez présenter les valeurs CMTime dans votre interface utilisateur, il peut être préférable d'extraire la valeur en secondes et de la transmettre à NSDateFormatter ou NSDateComponentsFormatter afin d'obtenir le support de paramètres régionaux approprié.

21
rickster

Ramenez la syntaxe modulo simple dans Swift 3:

Cette syntaxe a en fait été suggérée sur la liste de diffusion officielle d'Apple Swift ici , mais pour une raison quelconque, ils ont opté pour une syntaxe moins élégante.

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

Cette astuce de migration simple Swift 3 fait partie d'un guide de migration plus exhaustif Swift 3 avec de nombreuses informations (35k loc/8 jours de migration) http: // eon .codes/blog/2017/01/12/Swift-3-migration /

9
eonist

J'ai trouvé que ce qui suit fonctionne dans Swift 3:

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

totalSeconds est un TimeInterval (Double).

3
benwiggy