bmaliel
bmaliel

Reputation: 353

Swift unexpected error Cannot assign to '' in 'self'

I have a colours array and I am trying to get a random colour from it without getting the same two colours in a row and came across an error for previousNumber = randomNumber saying Cannot assign to 'previousNumber' in 'self'

var previousNumber: UInt32?

    func generateRandomNumber() -> Int {
        var coloursArrayLength = UInt32(coloursArray.count)
        var randomNumber = arc4random_uniform(coloursArrayLength)
        while previousNumber == randomNumber {
            randomNumber = arc4random_uniform(coloursArrayLength)
        }
        previousNumber = randomNumber
        var randomNumberInt = Int(randomNumber)
        return randomNumberInt
    }

How do I fix this?

Upvotes: 2

Views: 1216

Answers (1)

Airspeed Velocity
Airspeed Velocity

Reputation: 40973

I am guessing your function is actually inside a struct not shown in the code snippet, and the problem is you haven’t declared the function as mutating (i.e. the function can only be called on structs declared with let not var because it mutates self).

I’d also suggest breaking out the logic for generating the random number into a separate function for clarity and also to cut down on needing var so much:

func generateRandom(#upTo: UInt32, #notRepeatOf: UInt32?) -> UInt32 {
    // bear in mind though that you might need to handle if your coloursArray has one entry...
    precondition(upTo > 1 || notRepeatOf == nil , "avoid infinite loop")
    while true {
        let candidate = arc4random_uniform(upTo)
        if candidate != notRepeatOf { return candidate }
    }
}

struct S {
    var previousNumber: UInt32? = nil
    let coloursArray = [1,2,3,4]

    // note mutating keyword, fixes the "cannot
    // assign to self.previousNumber" error
    mutating func generateRandomNumber() -> Int {
        let newNumber = generateRandom(upTo: UInt32(coloursArray.count), notRepeatOf: previousNumber)
        previousNumber = newNumber
        return Int(newNumber)
    }
}

// if you declare the struct with let,
let a = S()
// it won’t let you call mutating funcs
// "Immutable value of type 'S' only has mutating members named 'generateRandomNumber'"
a.generateRandomNumber()

// have to declare with var
var b = S()
b.generateRandomNumber()

Upvotes: 7

Related Questions