Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialWill Seith
2,662 PointsNon repeating random number with UIColor
Hi,
I just completed "Build a Simple iPhone App with Swift 2.0" course and am trying to play around with the color model in that tutorial:
// // ColorModel.swift // FunFacts //
import UIKit import GameKit
struct ColorModel { let colors = [ UIColor(red: 90/255.0, green: 187/255.0, blue: 181/255.0, alpha: 1.0), //teal color UIColor(red: 222/255.0, green: 171/255.0, blue: 66/255.0, alpha: 1.0), //yellow color UIColor(red: 223/255.0, green: 86/255.0, blue: 94/255.0, alpha: 1.0), //red color UIColor(red: 239/255.0, green: 130/255.0, blue: 100/255.0, alpha: 1.0), //orange color UIColor(red: 77/255.0, green: 75/255.0, blue: 82/255.0, alpha: 1.0), //dark color UIColor(red: 105/255.0, green: 94/255.0, blue: 133/255.0, alpha: 1.0), //purple color UIColor(red: 85/255.0, green: 176/255.0, blue: 112/255.0, alpha: 1.0), //green color ]
func getRandomColor() -> UIColor {
let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(colors.count)
return colors[randomNumber]
}
}
Can anyone tell me how i can replace GKRandomSource so that random, non-repeating colors come up? It seems to throw people off when they press a button and the color stays the same.
Thanks
2 Answers
Will Seith
2,662 PointsOkay, code compiles fine in ViewController now, but results are about the same. Is there anyway to compare the previous randomNumber with the newly generated index in this statement?
if randomNumber == selectedIndex { randomNumber = (randomNumber + 1) % colors.count }
Just trying get something that works in the short term. Thank you for your help.
Anjali Pasupathy
28,883 PointsOne way to do it would to have another property representing the selected background color index (let's call this selectedIndex). Then you could keep track of which color is currently being used for the background color. If randomNumber equals selectedIndex, you could change randomNumber in some way so it doesn't equal selectedIndex (for example, by adding 1 to randomNumber and modding the result by colors.count to make sure you don't get an index out of bounds error). After doing this, you can set selectedIndex to randomNumber. NOTE: to change a property inside a struct using a function from that struct, you have to mark the function as mutating.
var selectedIndex: Int = 0
mutating func getRandomColor() -> UIColor {
var randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(colors.count)
if randomNumber == selectedIndex {
randomNumber = (randomNumber + 1) % colors.count
}
selectedIndex = randomNumber
return colors[randomNumber]
}
This is a bit of a quick hack - you'd also need to define the initial behavior of selectedIndex when you first set the background color. This implementation also takes away from the reusability of this ColorModel struct, because now you have a property inside ColorModel corresponding to some specific Object outside of the ColorModel.
I suppose another way to go about things would be to create a separate struct that keeps track of the indices, and modify ColorModel so that it can show the index of a particular color chosen - perhaps by adding a function where you input a UIColor, and the ColorModel returns the index of that UIColor in colors, or -1 if that UIColor isn't in colors?
I have to leave now, but I'll probably get back to you on this.
I hope this helps!
Will Seith
2,662 PointsOkay, I injected that into my code in the ColorModel and everything seemed fine until I ran simulator. Then an issue came up in the ViewController:
@IBAction func showFunFact() {
let randomColor = ColorModel().getRandomColor()
funFactButton.tintColor = randomColor
view.backgroundColor = randomColor
funFactLabel.text = factModel.getRandomFact()
}
Got back error message on line 2:
let randomColor = ColorModel().getRandomColor()
Message reads: "Cannot use mutating member on immutable value: function call returns immutable value"
This message also had "ColorModel()" underlined.
Thanks again!
Anjali Pasupathy
28,883 PointsI think what's going wrong here is that the compiler considers the instance ColorModel() to be a constant rather than a variable. The code you've written is almost equivalent to this code:
let colorModel = ColorModel()
let randomColor = colorModel.getRandomColor()
/*SET COLORS AND GET RANDOM FACT*/
Because colorModel is a constant, and getRandomColor() is a mutating function (which means it changes the Object it belongs to), the compiler sees this as attempting to change the constant colorModel. To fix this, you need to make colorModel a variable, and make that variable a property of the View Controller so it can keep track of the index beyond when you press the button:
/*AT THE TOP OF THE VIEW CONTROLLER*/
var colorModel = ColorModel()
/*INSIDE THE showFunFact FUNCTION*/
let randomColor = colorModel.getRandomColor()
//SET COLORS AND GET RANDOM FACT
Again, this solution is a quick hack, and there's probably a more elegant solution than this.
I hope this helps!
Will Seith
2,662 PointsWill Seith
2,662 PointsHi Anjali,
I finally saw my mistake. Everything works great.
Regards,
Will
Anjali Pasupathy
28,883 PointsAnjali Pasupathy
28,883 PointsAlright. I'm glad I could help!