I created an array and I'm populating the data (type Double) onto a table view. But when the app closes, all the data goes away! Im having trouble saving the array as a User Default so that when the user closes the app and opens it again, all of the info is still populated and available to see.
I set up an array called moneySpentArray, and this array holds all of a users entered transactions. After user clicks "submit", the IB action takes the input and sends it thru a function called addToMoneySpentArray
#IBAction func submitNewInfo(_ sender: UIButton) {
AddSubtractMoneyController.addToMoneySpentArray(amountISpent: Double(outputLabel.text!)!)
}
Below is the addToMoneySpentArray function that I send the data too, which then appends that amount into the 'moneySpentArray'.
class func addToMoneySpentArray( amountISpent: Double) {
moneySpentArray.append(amountISpent)
print(moneySpentArray)
}
Now in my SpendingHistoryVC- when the View loads, I use the array.reduce to add up the sum of the values in the array and display it in a text label called "youSpentThisMuch"- and Below this label will be the table view, which holds all the individual indexed amounts from the array also. Im confused on where and when to implement user defaults so that when a user enters a new amount through the IBAction above, it automatically stores and updates the array as a new user default. So even if the app is closed, their array history is still available to see.
override func viewDidLoad() {
super.viewDidLoad()
let arraySum: Double = AddSubtractMoneyController.moneySpentArray.reduce(0.0, +)
youSpentLabel.text = "\(arraySum)"
}
In addToMoneySpentArray save the data:
class func addToMoneySpentArray( amountISpent: Double) {
moneySpentArray.append(amountISpent)
UserDefaults.standard.set(moneySpentArray, forKey: "moneySpent")
print(moneySpentArray)
}
and in viewDidLoad load it
override func viewDidLoad() {
super.viewDidLoad()
let moneySpentArray = UserDefaults.standard.array(forKey: "moneySpent") as? [Double] ?? [Double]()
AddSubtractMoneyController.moneySpentArray = moneySpentArray
let arraySum = moneySpentArray.reduce(0.0, +)
youSpentLabel.text = "\(arraySum)"
}
Related
Hi I'm trying to shuffle an array which I can then use in all my IBAction functions thereafter in the order that I shuffled them. Example of code which is the same idea as what I have...
Class ViewContoller: UIViewContoller
Let numbers = [1,2,3,4,5]
override func viewDidLoad() {
super.viewDidLoad() }
I've tried to write a function here to create an array which has been shuffled so I can use that shuffled array ...
func shuffledArray() -> Array<Int> {
let numbersArray = numbers.shuffled()
return numbersArray }
let myListOfShuffledNumbers = shuffledArray()
Now this works in playground.. but when I try this my viewcontroller.swift I get error 'cannot use instance member 'shuffledArray' within property initializer; property initializers run before self is available.
So I know if I'm in a IBAction func I can run the function let shuffledNumbers = shuffledArray()and get an Array of shuffled numbers to use but my problem is I need to use that same shuffle order in another IBAction function. So how can I make a universal array of shuffled numbers to use anywhere on my view controller.
I've tried lazy var myListOfShuffledNumbers = shuffledArray()
This gets rid of my error but it doesn't help me because I get a 2 different list order when I use 'myListOfShuffledNumbers' in 2 different IBAction functions
What can I do ?? Thanks
You can define a property that you can access from anywhere in your ViewContoller, like this:
class ViewContoller: UIViewContoller {
let unshuffledNumbers = [1,2,3,4,5]
var myListOfShuffledNumbers = [Int]() /// here! it's still empty at first
#IBAction func firstButtonPressed(_ sender: Any) {
myListOfShuffledNumbers = unshuffledNumbers.shuffled()
}
#IBAction func secondButtonPressed(_ sender: Any) {
/// do something with myListOfShuffledNumbers here...
}
}
At first, myListOfShuffledNumbers is still an empty array of Ints. But inside your first IBAction, you can assign that to unshuffledNumbers.shuffled(). Then, you can access it from inside your second IBAction.
Also it might be easier to just write [Int] instead of Array<Int> -- they are the same thing.
func shuffledArray() -> [Int] {
let numbersArray = numbers.shuffled()
return numbersArray
}
If you want an array that is shuffled then just convert it to a set. Sets will not keep the original order of the array.
So basically I have a button and I need my UIImage to change randomly to one of three images in my array every time I click the button. Right now what happens when I click the button, is it just picks a random image and then when I click it again the image stays the same.
Here's what I have written inside my button:
#IBAction func scissorButton(_ sender: UIButton) {
playerChoice.image = scissor.png
computerChoice.image = computerArray[randomChoice]
}
Presumably you generated a random number once and stored that result in randomChoice. But you need to generate a new random number each time the button is tapped.
The simplest option is to do:
#IBAction func scissorButton(_ sender: UIButton) {
computerChoice.image = computerArray.randomElement()
}
You can try this to guarantee that each time you click the button will get a new non-similar random image
var old = 0
#IBAction func scissorButton(_ sender: UIButton) {
var randomChoice = 0
while randomChoice == old {
randomChoice = Int.random(in: 0..<computerArray.count)
}
old = randomChoice
computerChoice.image = computerArray[randomChoice]
}
Try this and it's work fine for me:
//Have an array of the name for your image like
let img = ["img1","img2","img3","img4"]
#IBAction func randomImageClick(_ sender: Any){
self.imageView.image = UIImage(named: img[Int.random(in: img.count)]) // Look out for range of index. its size must be equal your array count, otherwise it'll get index out of range
}
My context is as follows: I have a view controller that draws different room shapes. Each wall is a subclass of UIView. The model for the walls is as follows:
struct Wall {
let name: String
let number: Int
var length: CGFloat?
var attachedObjects: [WallObject]?
var isSelected: Bool
}
So each wall has a property that gets assigned one of the above ones.
When a tap happens on one wall the sender gets stored into an optional variable:
#objc fileprivate func changeWallProperties(sender: UITapGestureRecognizer) {
guard let tappedWall = sender.view as? RoomShapeDrawingV else {print("could not get wall"); return}
tappedWall.wallModel?.isSelected = true
selectedWallModel = tappedWall.wallModel
I have a collection view that displays objects that can go on the wall. When a cell is selected I get a WallObject type that is another struct for the contents of the collection view, the selection needs to be placed into the model for the selected wall:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let aWallHasBeenSelected = isWallSelected else {print("could not get the selected wall"); return}
if aWallHasBeenSelected {
print("a wall has been selected")
let wallObject = wallObjects[indexPath.item]
selectedWallModel?.attachedObjects?.append(wallObject)
The last line does nothing, [attachedObjects] is nil inside the model for that selected wall. I have found a solution on this post: Adding elements to optional arrays in Swift
But I want to know why this happens, if there is a logical error on my behalf or what. Is it because I use structs and I make copies of them, or there is something else happening?
I want to pass an array of strings through segue, but my app crashes. Here is what I have in the starting ViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "sendToOther") {
let svc = segue.destinationViewController as! OtherMinerals;
svc.toPass1 = String(DataSet[0])
svc.toPass2 = String(DataSet[1])
and this is what I have in the receiving ViewController
var toPass:String!
var toPass2:String!
so, I am passing every item separately through segue, but that's not elegant. I'd like to pass the whole array through, but for some reason I can't get the code right. Any genius out there to assist??
Just create a [DataSet] variable in your second ViewController and pass your whole DataSet array to your second ViewController instead of the two strings:
//second viewcontroller:
var dataSetArray:[DataSet]
//first viewcontroller:
svc.dataSetArray = yourDataSet
Change the type of the variable "toPass" to be [String]. If your DataSet is of the same type you can pass the array like so
svc.toPass = DataSet
Well I have been making a test app to continue my swift learning, today I came across a problem.
Basically I have a tableview and a detailview. For my tableview file I have some data that I am currently passing to the detailview, like the name that goes on the navigation bar, one image and some text, this data is stored in arrays on my tableview file, I use "prepareforsegue" to pass this information:
var names = ["name1","name2","name3"]
detailViewController.detailName = names[indexPath.row]
Then in my detailViewController I have variables set for that:
var detailName: String?
Then I use this for stuff, example: naming my navigation bar or setting an image in detailView:
navigationItem.title = detailName!
Now, what I dont get how to do is pass a whole array of information to a variable in my detailViewController. What I want to do is pass an array of images to use it on my detailView. I want to be able to iterate through the array of images with a button, I know how to set that up but I just need to know how to pass the array, right now I am just passing one of the values(one name, one image etc...)
Thanks for the help in advance.
It's not so different from what you have done.
Just add field for images in detailViewController, and then pass images using it. Images could be represented in [UIImage]. However, [String] can be also used for local filenames, and [NSURL] can be used for remote image urls.
code:
In DetailViewController:
var images: [UIImage]? // or var images: [UIImage] = []
In prepareForSegue:
detailViewController.images = YourImages
You seem to be asking for one of two things:
A UIImage array, which you can declare using var imageArray : [UIImage] = [] and then append whatever images you want to pass.
Alternatively, you can pass in a [AnyObject] array and cast its elements to a UIImage or String by doing
var objectArray : [AnyObject] = []
objectArray.append("test")
objectArray.append(UIImage(named: "test.png")!)
if let s = objectArray[0] as? String {
// Do something with the string
}
if let i = objectArray[1] as? UIImage {
// Do something with the image
}
if let s = objectArray[1] as? String {
// The above cast fails, this code block won't be executed
} else {
// ... but this one will
}
in the table view controller file:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get reference to the destination view controller
var detailVC = segue.destinationViewController as! DetailViewController
var detailImages: Array<UIImage> = []
detailImages.append(UIImage(named: "pup.png")!)
detailImages.append(UIImage(named: "cutepuppy.png")!)
detailVC.detailImages = detailImages;
}
and in the detail file:
var detailImages: Array<UIImage>?