How to have 'adaptive' structure name? - swift

So I am creating a struct and putting the results into an array like so
struct roundResults {
let round: Int
let team1Total: Int
let team2Total: Int
}
var allResults = [roundResults]()
Then I am filling the struct and appending it to the array like so
func createStruct(){
let (result) = roundResults(round:RoundNumber , team1Total:team1GameTotal , team2Total:team2GameTotal)
allResults.append(result)
}
And when I print the data from the array it gives me this
[Game.ScoreScreen.roundResults(round: 1, team1Total: 0, team2Total: 3),
Game.ScoreScreen.roundResults(round: 2, team1Total: 0, team2Total: 10)]
What I want to achieve is that instead of the struct being labeled like
Game.ScoreScreen.roundResults
I get something where roundResults represents the current round
I created a new variable and tried to use this var in lieu of round results when created the structure but this doesn't seem to work
func createCall(){
roundCall = "results" + String(RoundNumber)
}
What I would like to have is something like let (result) = (roundCall)(round:RoundNumber... so I have an easy way to pull each array depending on what round I am currently in and the printed data would look something like
[Game.ScoreScreen.results1(round: 1,
Game.ScoreScreen.results2(round: 2, etc...

You're currently just using the default print behaviour of structs.
You can make your struct conform to the [CustomStringConvertible][1] protocol by implementing thedescription` property. This lets you specify how you would like your struct to be represented in a string format, such as for printing.
Here's an example:
struct roundResults: CustomStringConvertible {
let round: Int
let team1Total: Int
let team2Total: Int
var description: String {
return "Round \(round) results: Team 1: \(team1Total) vs Team 2: \(team2Total)" // TODO: Adjust this to work as you wish.
}
}
Now when you print your array, it'll show:
["Round 1 results: Team 1: 0 vs Team 2: 3", "Round 2 results: Team 1: 0 vs Team 2: 10"]

Related

Cannot convert value of type '<Int>' to expected element type <Any>

I'm trying to learn swift, but I have a problem where using <Object> in Java would fix my problem I think, and the Apple doc says I should use <Any> but I keep getting errors.
I'm trying to build a memorize card game, I have the following models:
Theme.swift <- In charge of modeling different kind of themes for the cards, the idea is that the cards could have numbers, images etc, thats why it has a generic type after the name
import Foundation
import UIKit
struct Theme<Type> {
internal init(name: String, emojis: [Type], numberOfPairs: Int, cardsColor: UIColor) {
self.name = name
self.emojis = emojis
if(numberOfPairs > emojis.count || numberOfPairs < emojis.count) {
fatalError("Index out of bounds")
}
self.numberOfPairs = numberOfPairs
self.cardsColor = cardsColor
}
var name: String
var emojis: [Type]
var numberOfPairs: Int
var cardsColor: UIColor
}
I also have a Game model in charge of the game logic and cards model, I still have to implement a lot of stuff, but here's the code
import Foundation
struct Game {
var themes: [Theme<Any>]
var cards: [Card<Any>]
var score = 0
var isGameOver = false
var choosenTheme: Theme<Any>
init(themes: [Theme<Any>]) {
self.themes = themes
self.choosenTheme = self.themes.randomElement()!
cards = []
for index in 0..\<choosenTheme.numberOfPairs {
cards.append(Card(id: index*2, content: choosenTheme.emojis[index]))
cards.append(Card(id: index*2+1, content: choosenTheme.emojis[index]))
}
}
mutating func endGame() {
isGameOver = true
}
mutating func penalizePoints() {
score -= 1
}
mutating func awardPoints () {
score += 2
}
struct Card<T>: Identifiable {
var id: Int
var isFaceUP: Bool = false
var content: T
var isMatchedUP: Bool = false
var isPreviouslySeen = false
}
}
As you can notice I've used the Any type for creating an array of Cards and themes, cuz they could have strings, numbers or images
In my ViewModel I have the following code, where I'm trying to fill the Array of themes with two themes, one of string type of content, and the other one of Int:
import Foundation
import SwiftUI
class GameViewModel {
static let halloweenTheme = Theme<Int>(name: "WeirdNumbers", emojis: [1, 2, 4, 9, 20, 30], numberOfPairs: 6, cardsColor: .darkGray)
static let emojisTheme = Theme<String>(name: "Faces", emojis: ["🥰", "😄", "😜", "🥳", "🤓", "😎", "😋", "🤩"], numberOfPairs: 5, cardsColor: .blue)
var gameController: Game = Game(themes: [halloweenTheme, emojisTheme])
}
But I keep getting this or a similar error:
Cannot convert value of type 'Theme<Int>' to expected element type
'Array<Theme<Any>>.ArrayLiteralElement' (aka 'Theme<Any>')
Cannot convert value of type 'Theme<String>' to expected element type
'Array<Theme<Any>>.ArrayLiteralElement' (aka 'Theme<Any>')
And my mind is going crazy, I thought that by using [Theme<Any>] I would be able to have an array like this: [Theme<String>, Theme<Int>, Theme<Image>, ...] but it looks like not
Does anybody have a clue of what is going on here?
You can use a wrapper struct, basic example below. Note: if you need conformance to Codable, you need to implement encode/decode on your own.
struct Values<A> {
let value: A
}
struct Wrapper {
let wrappedValue: Values<Any>
}
class MyClass {
var wrappedValues: [Wrapper] = [Wrapper(wrappedValue: Values(value: "hello")), Wrapper(wrappedValue: Values(value: 1))]
}

filter array based on another

I have two arrays, one an array of array of profiles and one of the section names:
var sections: [Array<Profile>] = [friends, contacts, other]
var sectionNames = ["Friends", "Contacts", "Other Users"]
How do I filter the names based on whether the sections are empty? I get an error when I try the code below:
sectionNames.filter { index, _ in
sections[index].count > 0
}
Contextual closure type '(String) throws -> Bool' expect 1 argument, but two given
You can use zip and compactMap:
let nonEmptySections = zip(sections, sectionNames).compactMap { $0.isEmpty ? nil : $1 }
Using zip has the advantage that you don't get crashes if the two arrays have different sizes. On the other hand, it can lead to subtle bugs.
I'd recommend that you use a data structure to model you data instead:
struct Section {
let name: String
let profiles: [Profile]
}
This should ease the way you process the sections in your app. And by using #Alexander's suggestion, you can add an isEmpty property to the struct, making it even easier to use
extension Section {
var isEmpty: Bool { return profiles.isEmpty }
}
... later in the code
let nonEmptySections = sections.filter { !$0.isEmpty }
you can try something like this
var ar1:[Array<Int>] = [[1,2],[3,4,],[],[5,6]]
var ar2 = [1,2,3,4]
ar2 = (0 ..< ar1.count).filter {ar1[$0].count > 0}.map {ar2[$0]}
print(ar2) // [1, 2, 4]

Swift: How to keep updating a Dictionary inside another Dictionary correctly?

This is a little hard to explain, but I'll try my best. I am trying to update a Dictionary inside another Dictionary properly. The following code almost does what I need.
var dictionary = Dictionary<String, [Int : Int]>()
func handleStatsValue(tag: Int ) {
let currentValue: Int = dictionary["Score"]?[tag] ?? 0
dictionary["Score"] = [
tag : currentValue + 1
]
}
However, it seems the dictionary is overridden when the tag value changes (e.g. 1 to 2). I need Dictionary to have multiple dictionaries inside of it. Any tips or suggestions are deeply appreciated.
Edit: I'm trying to have multiple dictionaries nested inside a dictionary. It seems whenever the tag value is changed, the dictionary is overridden.
One way to write this would be:
func handleStatsValue(tag: Int) {
dictionary["Score", default: [:]][tag, default: 0] += 1
}
or, written without [_:default:]
func handleStatsValue(tag: Int) {
var scoreDictionary = dictionary["Score"] ?? [:]
scoreDictionary[tag] = (scoreDictionary[tag] ?? 0) + 1
dictionary["Score"] = scoreDictionary
}
However, it's not a good idea to use nested dictionaries to keep your data. Use a custom struct instead and try to avoid tags too:
struct DataModel {
var score: [Int: Int] = [:]
}
I think you need something like this to either increase the value for an existing tag or add a new tag if it doesn't exist
func handleStatsValue(tag: Int ) {
if var innerDict = dictionary["Score"] {
if let value = innerDict[tag] {
innerDict[tag] = value + 1
} else {
innerDict[tag] = 1
}
dictionary["Score"] = innerDict
}
}
Although the code looks a bit strange with the hardcoded key "Score", maybe it would be better to have multiple simple dictionaries instead, like
var score: [Int, Int]()
or if you prefer
var score = Dictionary<Int, Int>()

Extract Data from the struct in Swift

I have made a struct in which I'm passing my data. The data is in an array. I'm running a for loop to get the value out from it but I'm not getting full values. Suppose there is 5.0 value in an array when the loop runs. It first shows me 5, then ., and then 0. I want it to give 5.0 to me rather than seperate values.
My loop is this:
for price in ItemDataSource.sharedInstance.items[indexPath.row].price! {
print(price)
}
It shows this in console:
This is my class for Items:
class Item : NSObject {
var name : String?
var price : String?
var itemDdescription : String?
}
class ItemDataSource : NSObject {
var items = [Item]()
static let sharedInstance = ItemDataSource()
private override init() {}
}
Here I'm passing my values to it:
let item = Item()
item.name = itemName
item.price = String(result)
item.itemDdescription = String(describing: description)
ItemDataSource.sharedInstance.items.append(item)
Explanation:
ItemDataSource.sharedInstance.items[indexPath.row].price! is a String, iterating over it means to iterate over the characters that are in it. So if the `ItemDataSource.sharedInstance.items[indexPath.row].price!" is "5.0", it will print "5", "." and then "0".
To get the price for the given row, just use
let price = ItemDataSource.sharedInstance.items[indexPath.row].price!
as #John Ottenlips suggested.
Your loop may be unnecessary. indexPath.row will increase and allow you to iterate through your items in this delegate method. If you are just trying to get one price per cell try
let price = ItemDataSource.sharedInstance.items[indexPath.row].price!
print(price)
A general code smell is having a for loop inside a method you are returning a cell in.

Swift enums: Getting enum value for string enum from int value

We are using enums for some basic data structures like this:
enum Industry: String {
case Industry1 = "Industry 1", Industry2 = "Industry 2", Industry3 = "Industry 3"
static let allValues = [Industry1, Industry2, Industry3]
}
When we store the values in our database we store them as Ints/numbers. So for example the value for Industry might be 2 which would be Industry2.
How do I map the value 2, back to the relevant item in the enum? So I can retrieve the string value back?
You can do this to have arbitrary industry names:
enum Industry: Int {
case Industry1 = 1, Industry2, Industry3
static let allValues = [Industry1, Industry2, Industry3]
func industryName() -> String {
switch self {
case .Industry1: return "Industry A"
case .Industry2: return "Industry B"
case .Industry3: return "Industry C"
}
}
}
Example of usage:
let industry = Industry(rawValue: 2)
industry?.industryName() // prints "Industry B"
Industry is not represented in better way. You should pack industry name and code together in a better structure like this:
struct Industry {
var name: String
var code: Int
}
Now you could create a store class that can contain all industries.
Through enum you are not representing it very well. For saving one thing and displaying other thing.
Now if you have to save you can industry.code
And if you want to display industry.name
Based on your setup you could do:
let n = 2
let stringValue = Industry.allValues[n - 1].rawValue