J'ai défini le Swift -warn-long-function-bodies
Sur 90 millisecondes, pour voir quelles fonctions de mon projet prennent trop de temps à compiler (en raison de la vérification de type).
J'ai la méthode suivante:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix = row == 0 ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
(SectionType
est une énumération basée sur des chaînes)
Comme ci-dessus, cela prend 96 ms sur un MacBook Pro 2017. La première chose que j'ai essayée est de contourner l'interpolation de chaînes et d'utiliser \(sectionType.rawValue)
au lieu de \(sectionType)
, mais maintenant cela me donne 106 ms. Mauvais mouvement ...
Ensuite, j'ai changé:
let suffix = row == 0 ? "top" : "content"
à:
let suffix = "top"
L'avertissement disparaît, c'est donc l'opérateur ternaire qui pose problème.
J'ai plutôt essayé ceci:
let suffix: String = { // Note the type annotation!
if row == 0 {
return "top"
}
return "content"
}()
... mais maintenant c'est la fermeture qui prend 97 ms (la fonction entière, 101).
J'ai même essayé le plus explicite:
let suffix: String = {
if row == 0 {
return String("top")
} else {
return String("content")
}
}()
... et j'obtiens la fermeture: 94ms; fonction: 98 ms.
Que se passe-t-il?
Ma limite de 90 millisecondes est-elle trop basse? Je sais qu'il y avait (est?) Un bogue de vérification de type avec dictionnaire littéraux, mais cela semble quelque chose de complètement différent ...?
Mon environnement est Xcode 8.3.2 (8E2002), Swift: Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Mais attendez! Il y a plus ...
J'ai essayé ce corps de fonction:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
return "\(sectionType.rawValue)_top"
} else {
return "\(sectionType.rawValue)_content"
}
}
... et cela prend 97ms ~ 112ms!?
Addendum: J'ai transplanté la fonction et énuméré dans un projet minimal et propre (application vue unique) mis en place le même avertissement mais cela ne se produit pas. Je suis sûr que le projet dans son ensemble affecte cette méthode, mais je ne sais pas encore comment ...
Addendum 2: J'ai testé la version statique de ma fonction: utilisez le suffixe fixe "top" quelle que soit la valeur de row
(cela prend moins de 90 ms et ne déclenche aucun avertissement), - mais a ajouté le bloc if
suivant:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
print("zero")
} else {
print("non-zero")
}
let suffix: String = "top"
return "\(sectionType)_\(suffix)"
}
Cela me ramène à 96 ~ 98 ms! Donc, le problème se pose lorsque l'on compare la ligne à zéro?
Solution: J'ai continué à jouer avec mon code et j'ai découvert que si je remplaçais le bloc if
par une instruction switch
, le problème disparaissait:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix: String = {
switch row {
case 0:
return "top"
default:
return "content"
}
}()
return "\(sectionType)_\(suffix)"
}
(Je ne répondrai pas à ma propre question car je ne considère pas cela comme une explication de ce qui se passe réellement)
Je pense que c'est l'opérateur ternaire.
J'ai eu des résultats similaires dans Xcode 11 (~ 93 ms) mais le temps de compilation diminue à ~ 23 ms avec:
func someKey(_ sectionType: SectionType, row: Int) -> String {
var suffix = "top"
if row != 0 {
suffix = "content"
}
return "\(sectionType)_\(suffix)"
}
En changeant la logique sur cette ligne, je pense que nous pouvons prouver que c'est la logique ternaire car la méthode se réduit à ~ 1 ms. Je viens de faire de Row un booléen.
func someKey(_ sectionType: SectionType, row: Bool) -> String {
let suffix = row ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
De même (sans jeu de mots), changer la logique ternaire en let suffix = row != 0 ? "top" : "content"
divise par deux le temps de compilation. Ce qui est comparable à mon premier bloc de code. !=
est plus rapide pour Swift pour comprendre que ==
.