UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Using array elements to display images

Forums > SwiftUI

Hello, I am obviously very new to all of this as you will see. I very much appreciate your assistance. I am working on a playing card game that needs 2 decks and deals 10 cards to 4 players. I have an array of the deck where I shuffle it and assign 10 cards to the 4 hands. When I then try to display the cards of player 1 (p1Hand1), I get a Thread 1: Fatal error: Index out of range. For now I am just showing just player 1.

Here is the code so far:

struct showHands2: View { @State var p1Hand1: [String] = [] @State var cards = ["2_of_spades", "3_of_spades", "4_of_spades", "5_of_spades", "6_of_spades", "7_of_spades", "8_of_spades", "9_of_spades", "10_of_spades", "jack_of_spades", "queen_of_spades", "king_of_spades", "ace_of_spades", "2_of_hearts", "3_of_hearts", "4_of_hearts", "5_of_hearts", "6_of_hearts", "7_of_hearts", "8_of_hearts", "9_of_hearts", "10_of_hearts", "jack_of_hearts", "queen_of_hearts", "king_of_hearts", "ace_of_hearts", "2_of_clubs", "3_of_clubs", "4_of_clubs", "5_of_clubs", "6_of_clubs", "7_of_clubs", "8_of_clubs", "9_of_clubs", "10_of_clubs", "jack_of_clubs", "queen_of_clubs", "king_of_clubs", "ace_of_clubs", "2_of_diamonds", "3_of_diamonds", "4_of_diamonds", "5_of_diamonds", "6_of_diamonds", "7_of_diamonds", "8_of_diamonds", "9_of_diamonds", "10_of_diamonds", "jack_of_diamonds", "queen_of_diamonds", "king_of_diamonds", "ace_of_diamonds", "joker_red", "joker_black", "2_of_spades", "3_of_spades", "4_of_spades", "5_of_spades", "6_of_spades", "7_of_spades", "8_of_spades", "9_of_spades", "10_of_spades", "jack_of_spades", "queen_of_spades", "king_of_spades", "ace_of_spades", "2_of_hearts", "3_of_hearts", "4_of_hearts", "5_of_hearts", "6_of_hearts", "7_of_hearts", "8_of_hearts", "9_of_hearts", "10_of_hearts", "jack_of_hearts", "queen_of_hearts", "king_of_hearts", "ace_of_hearts", "2_of_clubs", "3_of_clubs", "4_of_clubs", "5_of_clubs", "6_of_clubs", "7_of_clubs", "8_of_clubs", "9_of_clubs", "10_of_clubs", "jack_of_clubs", "queen_of_clubs", "king_of_clubs", "ace_of_clubs", "2_of_diamonds", "3_of_diamonds", "4_of_diamonds", "5_of_diamonds", "6_of_diamonds", "7_of_diamonds", "8_of_diamonds", "9_of_diamonds", "10_of_diamonds", "jack_of_diamonds", "queen_of_diamonds", "king_of_diamonds", "ace_of_diamonds", "joker_red", "joker_black"]

var body: some View {
    VStack {
        Button(action: {
            cards.shuffle()
            print("shuffled drawdeck:", cards)
            let p1Hand1 = cards[0...9]
            print("p1Hand1: ",p1Hand1)
        }, label: {
            VStack {
                Image("Shuffle").resizable().frame(width: 150, height: 150)
                Text("Shuffle!").font(.largeTitle).foregroundColor(.orange)
            }
        })
        VStack {
            Text("Player 1 dealt hand")
            HStack {
                Image(p1Hand1[0])                 Thread 1: Fatal error: Index out of range
                    .resizable().scaledToFit()
                Image(p1Hand1[1])
                    .resizable().scaledToFit()
                Image(p1Hand1[2])
                    .resizable().scaledToFit()
                Image(p1Hand1[3])
                    .resizable().scaledToFit()
                }
            }
        }
    }
}

Thanks!

2      

You are defining 2 different values with the name p1Hand1.

@State var p1Hand1: [String] = []
//This creates the variable
let p1Hand1 = cards[0...9]
//This creates a constant with the same name as the variable

When you try to check the value using

Image(p1Hand1[0])

It is trying to access the var p1Hand1, which is still set to an empty array.

Try removing the let from this line, and see if it helps.

p1Hand1 = cards[0...9]

2      

thanks, I tried it, but get this error:

p1Hand1 = cards[0...9] Cannot assign value of type 'Array<String>.SubSequence' (aka 'ArraySlice<String>') to type '[String]'

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Oh right. You will need to do this instead...

p1Hand1 = Array(cards[0...9])

That will convert the ArraySlice into an Array before assigning it to p1Hand1.

2      

thanks, I tried it, but get this error:

p1Hand1 = cards[0...9] Cannot assign value of type 'Array<String>.SubSequence' (aka 'ArraySlice<String>') to type '[String]'

2      

I made the change: P1Hand1 = Array(cards[0...9])

But still get the Index out of range error

Image(p1Hand1[0]) Thread 1: Fatal error: Index out of range .resizable().scaledToFit()

Nuts! this seems like a simple thing to do. Is there a need to add some form of id: .self ??

2      

Oh, I see what's going on now. When your view first loads, it tries to display the cards from the players hand immediately. However, no cards have been added to the player's hand yet, until the "Shuffle" button gets tapped.

That is why the index is out of range. You are still dealing with an empty array when the program first tries to display the cards.

Probably the easiest way to fix that problem will be to use ForEach to display your card images. That way, if the array is empty, it just won't show anything, and won't try to access indeces that don't exist yet.

So, you could use something like this...

VStack {
    Text("Player 1 dealt hand")

    HStack {
        ForEach(p1Hand1, id: \.self) {
            Image($0)
                .resizable()
                .scaledToFit()
        }
    }
}

But you will still want to use the first suggestion I gave you as well.

2      

Hi @foremank and welcome to the forums!

When posting code to these forums, place three backticks ``` on the line before your code and three backticks ``` on the line after your code so that it will be formatted properly. You can also highlight an entire code block and click the </> button on the toolbar to wrap the block for you.

This makes it far easier to read and also makes it easier for other posters to copy/paste the code in order to test solutions and such.

Doing this will ensure that you end up with something like this:

func printSomething(_ thing: String?) {
    if let thing = thing {
        print(thing)
    } else {
        print("nothing there")
    }
}

instead of this:

func printSomething(_ thing: String?) { if let thing = thing { print(thing) } else { print("nothing there") } }

2      

thanks! this will display the player hands, off to the next challenge!

2      

So next related question, how do I show just a few of the 10 cards or need to display 2-3 rows of cards vs the ForEach with 1 long row of all the cards?

2      

You could just split it up into two separate HStacks using ForEach in each one. But you'll have to change up the ForEach a little bit.

VStack {
    Text("Player 1 dealt hand")

    HStack {
        ForEach(0..<5) { index in
            Image(p1Hand1[index])
                .resizable()
                .scaledToFit()
        }
    }

    HStack {
        ForEach(5..<10) { index in
            Image(p1Hand1[index])
                .resizable()
                .scaledToFit()
        }
    }
}

Or maybe use a LazyVGrid if that works better for what you want to do. https://www.hackingwithswift.com/quick-start/swiftui/how-to-position-views-in-a-grid-using-lazyvgrid-and-lazyhgrid

2      

Actually, that will probably put you back in a position where you'll get the index out of range errors. So, you'd probably need to wrap that whole VStack in an if block that checks if the array is empty before trying to show the VStack.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.