Steven Matthews
Steven Matthews

Reputation: 11335

Cannot use mutating member on immutable value: function call returns immutable value - not sure why value is immutable

Relatively new to Swift development. Trying to modify a couple functions someone else wrote. The goal is to leave the original pathway on the first time calling this after user login (that part hasn't been setup yet) and on subsequent calls, use another pathway.

So before writing the logic that will direct to first or non-first pass through, I am testing the non-first pass through logic.

Here's allOfferCards():

func allOfferCards() -> [OfferCard]{

    guard dataSource != nil else {
        return []
    }

    let numberOfCards = self.dataSource!.kolodaNumberOfCards(self)

    var offerCards = [OfferCard]()

    for i in 0..<numberOfCards {
        let offerCard = viewForCard(at: i)

        if let offerCard = offerCard {
            offerCards.append(offerCard as! OfferCard)
        }

    }

    return offerCards
}

And here is where I am trying to make the changes. The original logic reverses the return from allOfferCards(). I want to use a custom function called "shuffle" that will randomize the array.

func displayOfferCards() -> Void {
    // What was here originally
    //let offerCards = allOfferCards().reversed()
    var offerCards = allOfferCards().shuffle()

    for (index, offerCard) in offerCards.enumerated() {
        let delay = Double(index) * 0.2
        offerCard.display(delay: delay)
    }
}

Here's the shuffle function

extension Array
{
    /** Randomizes the order of an array's elements. */
    mutating func shuffle()
    {
        for _ in 0..<10
        {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}

However when I try to run this I get the error in the title - can't use a mutating member on an immutable value. However I'm not sure why allOfferCards() is generating an immutable value - var offerCards is defined using a var keyword, not a let keyword - this should mean it is mutable correct?

What am I doing wrong here?

Upvotes: 0

Views: 3171

Answers (2)

Alexander
Alexander

Reputation: 63399

Supplementing @Dávid Pásztor answer.

Instead of using a mutating functions (shuffle()), you can use a varient that returns a shuffled copy (shuffled()), similar to sort() vs sorted(). Since there's no variable being mutated, it can all be done in-line:

func displayOfferCards() {
    for (index, offerCard) in allOfferCards().shuffled().enumerated() {
        offerCard.display(delay: Double(index) * 0.2)
    }
}

See this answer for an implementation of shuffle(), shuffled().

Upvotes: 0

David Pasztor
David Pasztor

Reputation: 54805

The issue is that before assigning the return value of a function, the value itself is immutable, so calling a mutating function on it cannot be directly done. You should assign the return value first to a mutable variable, then call the mutating function on it.

func displayOfferCards() -> Void {
    var offerCards = allOfferCards()
    offerCards.shuffle()

    for (index, offerCard) in offerCards.enumerated() {
        let delay = Double(index) * 0.2
        offerCard.display(delay: delay)
    }
}

Upvotes: 1

Related Questions