swift中的index(where :)方法生成错误的索引

时间:2018-04-23 02:48:41

标签: ios arrays swift closures indexoutofrangeexception

我收到的数组索引超出范围错误。我有两个数组cardsCurrentlyInPlaycurrentCardsSelected。此游戏中的每张卡都有一个唯一的ID。我试图找到cardsCurrentlyInPlaycardIDcardID中卡currentCardsSelected匹配的卡片索引。我这样做是通过使用带有闭包的index(where:)方法实现的。我的闭包只是检查ID是否匹配,它们显然是匹配的,因为我使用!来解开它们并且应用程序不会在那里崩溃。似乎index(where:)方法返回错误的索引。我已经看了几个小时了,我不明白最近发生了什么。

下面是代码:

    let indexOfFirstCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[0].cardID)}))!
    let indexOfSecondCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[1].cardID)}))!
    let indexOfThirdCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[2].cardID)}))!

    if deck.isEmpty && selectedCardsMakeASet() {

        /* Remove the old cards */
        cardsCurrentlyInPlay.remove(at: indexOfFirstCard)
        cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
        cardsCurrentlyInPlay.remove(at: indexOfThirdCard) // where code is blowing up

        currentCardsSelected.removeAll()

        /* Return indicies of cards to clear from the UI */
        return .deckIsEmpty(indexOfFirstCard, indexOfSecondCard, indexOfThirdCard)

    }

Here is where I am getting an index out of range error

Each card has a unique ID, so my second card in <code>currentCardsSelected</code> has an ID of 47. I base the closure that I pass into the index function (see first picture) based off this ID. Basically, find the index of the card in <code>cardsCurrentlyInPlay</code> whose cardID matches the cardID of the card in <code>currentCardsSelected</code>. Either I have completely lost my mind or the index(where:) method is returning the wrong index.

2 个答案:

答案 0 :(得分:3)

当您获取时, 的索引正确,但当您删除其他卡时 错误。考虑:

var a = ["x", "y", "z"]
let indexOfX = a.index(of: "x")!  // returns 0
let indexOfZ = a.index(of: "z")!  // returns 2
a.remove(at: indexOfX)  // removes "x"; now a = ["y", "z"]
a.remove(at: indexOfZ)  // index 2 is now out of bounds

您可以将呼叫交错到index(of:)remove(at:),但更好的方法是一次性删除所有三张卡片,如下所示:

let selectedCardIDs = currentCardsSelected.map { $0.cardID }
cardsCurrentlyInPlay = cardsCurrentlyInPlay.filter { card in
    !selectedCardIDs.contains(card.cardID)
}

请注意,这有一个额外的好处,即避免强行打开,这是一种更健全的逻辑。

答案 1 :(得分:0)

这是因为出界。

前两个代码出手后。 cardsCurrentlyInPlay.remove(at: indexOfFirstCard)&amp; cardsCurrentlyInPlay.remove(at: indexOfSecondCard) cardsCurrentlyInPlay中只有一个元素。 然后,如果您执行cardsCurrentlyInPlay.remove(at: indexOfThirdCard),程序将崩溃。