web-dev-qa-db-fra.com

Comment attraper "Index out of range" dans Swift?

Je voudrais vraiment utiliser un bloc d’essais classique plus simple dans mon code Swift mais je ne trouve rien qui le fasse.

J'ai juste besoin:

try {
// some code that causes a crash.
}
catch {
// okay well that crashed, so lets ignore this block and move on.
}  

Voici mon dilema, lorsque la TableView est rechargée avec de nouvelles données, certaines informations sont toujours localisées dans RAM qui appelle didEndDisplayingCell sur une table avec une source de données fraîchement vide pour planter.

Donc, j'ai souvent jeté l'exception Index out of range

J'ai essayé ceci:

func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    do {
        let imageMessageBody = msgSections[indexPath.section].msg[indexPath.row] as? ImageMessageBody
        let cell = tableView.dequeueReusableCellWithIdentifier("ImageUploadCell", forIndexPath: indexPath) as! ImageCell
        cell.willEndDisplayingCell()
    } catch {
        print("Swift try catch is confusing...")
    }
}

J'ai aussi essayé ceci:

func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    print(indexPath.section)
    print(indexPath.row)

    if msgSections.count != 0 {
        if let msg = msgSections[indexPath.section].msg[indexPath.row] as? ImageMessageBody {
            let cell = tableView.dequeueReusableCellWithIdentifier("ImageUploadCell", forIndexPath: indexPath) as! ImageCell
            cell.willEndDisplayingCell()
        }
    }
}

Il s’agit d’un bloc de code de priorité très basse et j’ai perdu beaucoup de temps à essayer de déterminer le gestionnaire d’erreurs intégré à Swift fonctionne dans ce qui semble être des situations extrêmement uniques Il y a des tas de scénarios, comme celui-ci, où le code peut planter et que cela n'aura aucun effet sur l'expérience de l'utilisateur.

En bref, je n'ai besoin de rien d'extraordinaire, mais Swift semble avoir des gestionnaires d'erreurs extrêmement spécifiques qui diffèrent selon que j'obtiens une valeur d'une fonction ou une valeur de retour l'index du tableau qui peut ne pas exister.

Existe-t-il un essai simple sur Swift comme tous les autres langages de programmation populaires?

29
Matt Andrzejczuk

Comme suggéré dans les commentaires et autres réponses, il est préférable d'éviter ce genre de situation. Cependant, dans certains cas, vous pouvez vérifier si un élément existe dans un tableau et s'il le renvoie en toute sécurité. Pour cela, vous pouvez utiliser l'extension de tableau ci-dessous pour retourner en toute sécurité un élément de tableau.

Swift 3

extension Collection where Indices.Iterator.Element == Index {
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Swift 2

extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}
  • De cette façon, vous ne frapperez jamais Index out of range
  • Vous devrez vérifier si l'élément est nil

se référer cette question pour plus


Essayer le code Swift3 dans une aire de jeu sous Xcode 8.3.2 conduit toujours à un "crash" quand je laisse ar = [1,3,4], puis que v = ar [5]. Pourquoi? - Thomas Tempelmann le 17 mai à 17h40

Vous devez utiliser notre indice personnalisé donc au lieu de let v = ar[5], ce sera let v = ar[safe: 5].

Valeur par défaut de array.

let boo = foo[index]

Ajouter utiliser l'indice personnalisé.

let boo = fee[safe: index]

// And we can warp the result using guard to keep the code going without throwing the exception.
guard let boo = foo[safe: index] else {
  return
}
42
Penkey Suresh

Swift's Traitement des erreurs (do/try/catch) est pas la solution pour des exceptions d'exécution comme "index out of range".

Une exception d’exécution (vous pouvez également voir ces appels appelés , piège , , erreur fatale , , échec d’assertion , etc.) est le signe d'une erreur de programmation. Sauf dans les versions -Ounchecked, Swift garantit généralement que ces programmes planteront votre programme plutôt que de continuer. pour exécuter dans un état incorrect/non défini.Ces types de blocages peuvent survenir de la décompression forcée avec !, du désencapsulement implicite, de l'utilisation abusive de unowned références, d'opérations entières/conversions qui débordent, fatalError() s et precondition() s et assert() s, etc. (et, malheureusement, les exceptions Objective-C.)

La solution consiste simplement à éviter ces situations . Dans votre cas, vérifiez les limites du tableau:

if indexPath.section < msgSections.count && indexPath.row < msgSections[indexPath.section].msg.count {
    let msg = msgSections[indexPath.section].msg[indexPath.row]
    // ...
}

(Ou, comme le dit rmaddy dans des commentaires - examinez pourquoi ce problème se produit! Il ne devrait vraiment pas arriver du tout.)

27
jtbandes

Swift 4:

extension Collection where Indices.Iterator.Element == Index {
    subscript (exist index: Index) -> Iterator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

sage:

var index :Int = 6 // or whatever number you need
if let _ = myArray[exist: index] {
   // do stuff
}

ou

var index :Int = 6 // or whatever number you need
guard let _ = myArray[exist: index] else { return }
13

Vous pouvez essayer une approche différente à cela. Cela fonctionnera sûrement!

if msgSections != nil {
    for msg in msgSections[indexPath.section] {
        if msgSections[indexPath.section].index(of: msg) == indexPath.row {
            (Code)
        }
}
1
Nimish Sharma