I have a collection view in VC1 embedded in a navigationController. The collection view contains buttons that go to VC2. When make changes in VC2 and close that VC, I want the collectionView in VC1 to update. However, the functions that make up the collectionView aren't inside viewWillAppear; how can I make VC1 refresh after closing VC2? I have tried a few different things written at the bottom of VC2
VC1
import UIKit
class HerdViewCell: UICollectionViewCell {
@IBOutlet weak var horseNameOutlet: UILabel!
@IBOutlet weak var baseLayer: UIImageView!
}
var myHorses = [
Horse(name: "Donnerhall", idNumber: 1, gender: "Stallion", age: 1),
Horse(name: "Celeste", idNumber: 2, gender: "Mare", age: 1),
Horse(name: "Kara", idNumber: 3, gender: "Mare", age: 1)
]
var horseIndex = 0
import UIKit
class HerdViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
@IBOutlet weak var herdCollectionView: UICollectionView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
herdCollectionView.delegate = self
herdCollectionView.dataSource = self
}
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) - Int {
return myHorses.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) - UICollectionViewCell {
var cell = UICollectionViewCell()
if let horseCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? HerdViewCell {
let horseTag = "\(myHorses[indexPath.row].name ?? "none") \n\(myHorses[indexPath.row].gender), \(myHorses[indexPath.row].age) years"
horseCell.horseNameOutlet.text = horseTag
horseCell.baseLayer.image = myHorses[indexPath.row].basePhenotype
cell = horseCell
horseIndex = indexPath.row
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
horseIndex = indexPath.row
performSegue(withIdentifier: "horseViewerSegue", sender: self)
}
}
}
VC2
import UIKit
class HorseViewController: UIViewController {
@IBOutlet weak var horseNameOutlet: UILabel!
@IBOutlet weak var horseGenderOutlet: UILabel!
@IBOutlet weak var horseAgeOutlet: UILabel!
@IBOutlet weak var baseLayer: UIImageView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updateHorse()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
func updateHorse(){
horseNameOutlet.text = myHorses[horseIndex].name
horseGenderOutlet.text = myHorses[horseIndex].gender
horseAgeOutlet.text = "\(String(myHorses[horseIndex].age)) years"
baseLayer.image = myHorses[horseIndex].basePhenotype
}
@IBAction func sellHorse(_ sender: UIButton) {
myHorses.remove(at: horseIndex)
//dismissing won't work, because the app closes the navigationController instead of going back to the root of the navigation controller
//dismiss(animated: true, completion: nil)
//If I navigate to the root of the navigationController, the collectionView is as I left it instead of removing a horse
// self.navigationController?.popViewController(animated: true)
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am unsure what I am doing wrong here. I want to limit the values in var training to 1.0. I have set up a test where the two printed values should be different, but the value is not changed even though a number higher than 1.0 is found.
struct Horse {
var training : [Float]
}
var myHorses = [
Horse(training: [1.5,0,0,0,0,0,0]),
Horse(training: [0,0,0,0,0,0,0]),
Horse(training: [0,0,0,0,0,0,0])
]
var horseIndex = 0
print(myHorses[horseIndex].training[0])
for var skills in myHorses[horseIndex].training {
if skills 1.0 {
print("value 1.0 found")
skills = 1.0
}
}
print(myHorses[horseIndex].training[0])
I have a stepper that changes a value in my Horse struct, but at the moment I can only increase the value. I need to "refresh" the page to show the new value in the interface, and that starts the process from scratch. Also, if the horse has a value already the stepper changes it to 0 before proceeding.
func addButtons() {
for (feed,amount) in feedInventory where amount 0 {
let filteredProducts = feedProducts.filter { $0.code.contains(feed)}
for feedProduct in filteredProducts {
let horizontalStack = UIStackView()
horizontalStack.axis = .horizontal
horizontalStack.alignment = .firstBaseline
let rationAmount = UILabel(frame: .zero)
let rationIndex = Int(rationArrayPosition[feedProduct.code]!)
rationAmount.text = "\(myHorses[horseIndex].ration[rationIndex])"
horizontalStack.addArrangedSubview(rationAmount)
let stepper = UIStepper(frame: .zero)
stepper.minimumValue = 0
stepper.maximumValue = 900
stepper.wraps = false
stepper.autorepeat = false
stepper.addTarget(self, action: #selector(stepperValueChanged(_:)), for: .valueChanged)
stepper.accessibilityLabel = "\(feedProduct.code)"
horizontalStack.addArrangedSubview(stepper)
feedStack.addArrangedSubview(horizontalStack)
}}}
func removeButtons() {
let rows = feedStack.arrangedSubviews
.filter {$0 is UIStackView}
for row in rows {
feedStack.removeArrangedSubview(row)
row.removeFromSuperview()
}}
@objc func stepperValueChanged(_ sender:UIStepper!) {
let rationIndex = rationArrayPosition[sender.accessibilityLabel!]
//This is where I have trouble*
myHorses[horseIndex].ration[rationIndex ?? 00] += Int(sender.value)
removeButtons()
addButtons()
}
I can't use = Int(sender.value) because this resets to 0 each time I press the button, but how can I update the values without using removeButtons() and addButtons()?
Let me know if more code is needed, I think I'm just using the stepper incorrectly though
I have a stack view to which I add some buttons when the UI loads. I have made these work quite well as they are, but I want to simplify my interface. Instead of showing a button for each feed, I want to add a horizontal stack view showing a label and a stepper to alter the values for each feed type.
This is what I have now:
struct FeedProduct {
var name : String
var code : String
}
var feedProducts = [
FeedProduct(name: "Oats", code: "oats"),
FeedProduct(name: "Straw", code: "straw"),
FeedProduct(name: "Salt", code: "salt")
]
var feedInventory: [ String : Int ] = [
"straw" : 10,
"oats" : 20,
"salt" : 0
]
func addButtons() {
for (key,value) in feedInventory{
let button = UIButton()
button.addTarget(self, action: #selector(self.selectFeed(sender:)), for: .touchUpInside)
let filteredProducts = feedProducts.filter { $0.code.contains(key)}
for feedProduct in filteredProducts {
if value > 0 {
button.setTitle(" \(feedProduct.name) , amount: \(value)", for: UIControl.State.normal)
button.accessibilityIdentifier = feedProduct.code
feedStack.addArrangedSubview(button)
}}}}
@objc func selectFeed(sender: UIButton){
//this is where assign the selected feed type, and I had an external stepper button to alter the amount of feed
}
My plan is to change the addButtons function so that instead of adding buttons, it will add a horizontal stack view containing a label and a stepper for each feed above 0 in the inventory. This would make my interface much cleaner. Not sure if this is even possible, maybe there are better ways of doing it. Any tips would be really helpful!
I have a stack view to which I programmatically add buttons. There are "tabs" where the user can select different categories. However, when I select a new category, the new buttons are just added underneath. Is there a way to delete the contents of tackStack? Then I could call that function before adding buttons when a new category is selected.
I know there is something called removeArrangedSubview, but I am unsure how to use this on buttons that are added programmatically
@IBOutlet weak var tackStack: UIStackView!
func addButtons() {
for (key,value) in tackInventory{
let button = UIButton()
button.setTitle("\(foundColor) \(product.brand) \(product.category), amount: \(value)", for: UIControl.State.normal)
tackStack.addArrangedSubview(button)
}
}
I have an array of products and a separate dictionary of inventory. I want to be able to use the keys of the dictionary to "look up" the colorName within the product catalog using the name of the item found in the dictionary. I know you can search for item position within an array, but how to you do this if it is an array within an array?
The products:
Product(brand: "Academia", category: "Bandages", colorName: [ "Blue", "Green", "Purple", "Red" ], item: ["academiaBandagesBlue", "academiaBandagesGreen", "academiaBandagesPurple", "academiaBandagesRed"])
The inventory
var tackInventory: [ String : Int] = [
"academiaBandagesBlue" : 1,
"academiaBandagesGreen" : 0,
"academiaBandagesPurple" : 0,
"academiaBandagesRed" : 0
I can search for a value in an array if I know the position of the item in the array, but how can I search by another parameter like ID number or name?
import UIKit
struct Horse {
var name : String
var idNumber : Int
var sire : String
var dam : String
}
var myHorses = [
Horse(name: "Donnerhall", idNumber: 1, sire: "Unknown", dam: "Unknown"),
Horse(name: "Celeste", idNumber: 2, sire: "Unknown", dam: "Unknown"),
Horse(name: "Kara", idNumber: 3, sire: "1", dam: "2"),
]
func lookupHorse() {
let index = 1
print(myHorses[index].idNumber)
print(myHorses[index].name)
}
I have had a similar problem previously and someone suggested keypaths might be the answer
I want to add to the number of blueBandages
struct Product {
var brand: String
var option1: String
var option2: String
var item1: String
var item2: String
}
//inventory
var blueBandages = 0
var redBandages = 0
var yellowBandages = 0
var greenBandages = 0
//catalog
let products = [
Product(brand: "Academia", option1: "Blue", option2: "Red", item1: "blueBandages", item2: "redBandages"),
Product(brand: "Academia", option1: "Yellow", option2: "Green", item1: "yellowBandages", item2: "greenBandages")]
func buy() {
//???
}
The obvious way is the following:
func buy() {
blueBandages += 1
}
But this will require a lengthy If statement to identify which item to add. I will have to add to the if statement every time I add an item to the catalog
var selectedProduct = 0
if selectedProduct == "Academia blueBandages":
blueBandages += 1
I wish I could "unwrap" some string as executable code, but I don't think this exists.
func buy() {
Code(product[1].item1) =+ 1
}
//if only this worked the same as the previous code chunk
Maybe keypaths are the answer? I haven't been able to make it work, because my key path is still acting like a string and not executable code
I have a few places in my app where I need to alter a property of a struct, but it takes a lot of code.
The struct, arrays and variables:
struct Horse {
var name: String
var basicTraining : Float
var rhythm : Float
var suppleness : Float
var myHorses = [
Horse(name: "Donnerhall", basicTraining : 0.5, rhythm : 0.2, suppleness : 0.1),
Horse(name: "Bjork", basicTraining : 0.4, rhythm : 0.3, suppleness : 0.1)
]
var horseIndex = 0
var scaleCode = [ basicSkills, rhythmSkills, supplenessSkills ]
var currentScaleCode = basicSkills
var skillIndex = 0
The current code (takes a lot of lines):
func trainHorse() {
if myHorses[horseIndex].basicTraining > 100 {
myHorses[horseIndex].basicTraining = 100 }
if myHorses[horseIndex].basicTraining < 100 {
myHorses[horseIndex].basicTraining += currentScaleCode[skillIndex].basicBoost }
if myHorses[horseIndex].rhythm > 100 {
myHorses[horseIndex].rhythm = 100 }
if myHorses[horseIndex].rhythm < 100 {
myHorses[horseIndex].rhythm += currentScaleCode[skillIndex].rhythmBoost }
if myHorses[horseIndex].suppleness > 100 {
myHorses[horseIndex].suppleness = 100 }
if myHorses[horseIndex].suppleness < 100 {
myHorses[horseIndex].suppleness += currentScaleCode[skillIndex].supplenessBoost }
}
What I would like is to simplify this code by doing something like this:
var currentTraining = basicTraining //or rhythm or suppleness
currentBoost = basicBoost
func trainHorse() {
if myHorses[horseIndex].currentTraining > 100 {
myHorses[horseIndex].currentTraining = 100 }
if myHorses[horseIndex].currentTraining < 100 {
myHorses[horseIndex].currentTraining += currentScaleCode[skillIndex].currentBoost }
But when I call a property using a placeholder, I get the error "Value of type 'Horse' has no member..." I have tried using different types of brackets and parentheses without luck
I want to change some properties in my array. I recently discovered that I am only able to do this if I directly specify the number of the element in the array I am working with. This is tricky because I always assumed you could edit an array using a variable. I have been using a variable to save myself a lot of code. In some view controllers, the array can have hundreds of items... my var is a workaround that uses the button tag to identify the horse that is selected for editing
import UIKit
struct Horse{
var name: String
var age: Int
}
var myHorses = [
Horse(name: "Billy", age: 3),
Horse(name: "Merc", age: 5)
]
//horse selected for editing
var currentHorse = myHorses[0]
//tag of the button that is pressed
var horseIndex = sender.tag
//trying to edit age
currentHorse.age = 10
//I thought these would be the same
print(myHorses[1].age)
print(merc.age)
I want to find a random number in a range that goes 1-100. I want the number to be the average of these two:
var firstNumber = 20
var secondNumber = 30
but I want it to have some "variability"
var variability = Int.random(in:-12...12)
result: Int.random(in: (firstNumber)...(secondNumber) + variability)
The problem is, the result cannot go beyond 1-100. If the first number is close to the end of the range, variability could make the result go beyond 1-100. I tried using an If statement, but this involves writing a lot of extra code for each factor I am adding variability to. Any suggestions?
I have a function that calculates a random genotype. At the moment all genes are equally likely. In reality, some genes are more likely than others. How can I change my function to be more realistic? I have attached some example percentages (they don't add up yet)
//grey 10% of "G" appearing, 90% chance of "g" appearing
greGenotype = ["G", "g"][Int.random(in:0...1)]+["G", "g"][Int.random(in:0...1)]
//single tobiano 5% of "To" appearing, 95% of "to" appearing
tobGenotype = ["To", "to"][Int.random(in:0...1)]+["To", "to"][Int.random(in:0...1)]
}
I have this var:
//genes
var extGene = "ee"
var agoGene = "aa"
var creGene = "crcr"
//genotype
var genotype = extGene + agoGene + creGene
The genotype can appear in different variations like "eeaacrcr", "EeAaCrcr" or "EEAACrCr", but there are a lot more combinations. Sometimes the letters in the genes can appear in random order, for example "Ee" or "eE". I am using this switch statement which is getting too complex:
switch (extGene, agoGene, creGene) {
case
("EE", "aa", "crcr"),
("Ee", "aa", "crcr"),
("eE", "aa", "crcr"):
basPhenotype = (blackArray.randomElement()!)
case
("ee", "aa", "crcr"),
("ee", "Aa", "crcr"),
("ee", "aA", "crcr"),
("ee", "AA", "crcr"):
basPhenotype = (chestnutArray.randomElement()!)
case
("EE", "AA", "crcr"),
("Ee", "AA", "crcr"),
("eE", "AA", "crcr"),
("EE", "Aa", "crcr"),
("EE", "aA", "crcr"),
("Ee", "Aa", "crcr"),
("eE", "Aa", "crcr"),
("Ee", "aA", "crcr"),
("eE", "aA", "crcr"):
basPhenotype = (bayArray.randomElement()!)
Instead it would be nice to just search the genotype for single letters, irrespective of what order they are in, maybe something like this
if genotype contains "e" + "E" {
uiImage = image1
}
if genotype contains "ee" {
uiImage = image2
}
Does anyone know of a way to simplify the code?
Hi! I am working on a pickerView with two components. I have an array (myHorses) with one stallion and two mares. If I run the app I get an "out of range" error at line 33. If I add another stallion to the array this goes away. Also, the image outlets are showing the images for the stallion on both outlets. How can I make the app work when there is just one member of a gender, and also show the correct images?
class BreedingViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
let myStallions = myHorses.filter({ $0.gender == "Stallion" })
let myMares = myHorses.filter({ $0.gender == "Mare" })
var sireIndex = 0
var damIndex = 0
@IBOutlet weak var horsePicker: UIPickerView!
@IBOutlet weak var sireBaseLayer: UIImageView!
@IBOutlet weak var damBaseLayer: UIImageView!
var recievedString: String = ""
func numberOfComponents(in sirePicker: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return myStallions.count
}
else {
return myMares.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
let stallions = myStallions[row]
let mares = myMares[row]
if component == 0 {
return "\(stallions.name), health: \(stallions.health)"
}
else {
return "\(mares.name), health: \(mares.health)"
}
}
func pickerView(_ horsePicker: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
var chosenSire = myHorses[sireIndex]
var chosenDam = myHorses[damIndex]
if component == 0 {
let theSire = myHorses[row]
sireNameOutlet.text = theSire.name
chosenSire = theSire
sireBaseLayer.image = chosenSire.basePhenotype
}
else {
let theMare = myHorses[row]
damNameOutlet.text = theMare.name
chosenDam = theMare
damBaseLayer.image = chosenDam.basePhenotype
}
}
override func viewDidLoad() {
super.viewDidLoad()
horsePicker.delegate = self
horsePicker.dataSource = self
}
}
I have an array:
var myHorses = [
Horse(name: "Donnerhall", idNumber: 1, gender: "Stallion"),
Horse(name: "Mischa", idNumber: 2, gender: "Mare")]
I want to make a picker view with only the names from the array showing. I have previously used button.tag in another VC to find the horseIndex. Is there a way to list only the names in the picker view?
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myHorses[row]
//pasted from another VC, maybe something like this can work here
var horseName = for horseIndex in myHorses.indices {
let horse = myHorses[horseIndex]
button.tag = horseIndex
}
Thanks in advance!