Hi, i'm new to swift. I was trying to make a deck of card but i keep getting this message. Does anyone have an idea on how to fix it?
Could you also post the type declarations for Card
etc.?
Moving this to Using Swift
Xcode shows four errors.
First Error
let myCard = Card(rank: aRank!, suit: aSuit!)
^ Cannot invoke initializer for type 'Card' with an argument list of type '(rank: Card.Rank, suit: Card.Suit)'
We can't diagnose this without seeing the definition of the Card
type.
Second Error
var deckOne = generateDeckOfCards()
^ Cannot use instance member 'generateDeckOfCards' within property initializer; property initializers run before 'self' is available
This error is telling you that you can't call generateDeckOfCards
from this location because generateDeckOfCards
is an instance method. The reason Swift doesn't let you call an instance method here is because, in general, the instance method might rely on the instance being fully initialized, and it's not fully initialized yet.
In this particular case, your generateDeckOfCards
method doesn't use any instance methods or properties at all, so you can change it to be a static
or class
method instead:
static func makeDeckOfCards() -> [Card] {
var myDeckOfCards: Array = [Card]()
etc.
}
// Assuming this class is named DeckOfCards...
var deckOne = DeckOfCards.makeDeckOfCards()
If you fix the Second Error, Swift will give you an error on the next line:
var singleCard = deckOne[51]
^ Cannot use instance member 'deckOne' within property initializer; property initializers run before 'self' is available
This new error is very similar to the Second Error. You can't use one instance property in another property's initializer. Instead, you need to write an instance initializer:
var deckOne = DeckOfCards.makeDeckOfCards()
var singleCard: Card
init() {
// Property initializers run before init runs,
// so deckOne is already initialized.
singleCard = deckOne[51]
}
Third Error
var theCard = cardsInfo(singleCard)
^ Cannot use instance member 'cardsInfo' within property initializer; property initializers run before 'self' is available
This is the same error as the Second Error. You can't call the instance method cardsInfo
here.
Since cardsInfo
doesn't use any instance properties or methods, and uses several Card
properties, you can replace cardsInfo
with a computed property on the Card
type. Delete your cardsInfo
method and put this at global scope:
extension Card {
var cardInfo: (name: String, emoji: String, points: Int) {
return (name: rank.rankDescription(), emoji: suit.rawValue, points: rank.cardsValue())
}
}
Then you can try to declare theCard
like this, and get a different error:
var theCard = singleCard.cardInfo
^ Cannot use instance member 'singleCard' within property initializer; property initializers run before 'self' is available
This is the same error you got after fixing the Second Error, and you fix this the same way. Initialize theCard
in init
:
var deckOne = DeckOfCards.makeDeckOfCards()
var singleCard: Card
var theCard: (name: String, emoji: String, points: Int)
init() {
// Property initializers run before init runs,
// so deckOne is already initialized.
singleCard = deckOne[51]
theCard = singleCard.cardInfo
}
Fourth Error
theCard.name
^ Expected declaration
You are directly inside a class
or struct
declaration here, so the only things allowed are declarations. theCard.name
is not a declaration. Declarations usually start with let
, var
, or func
.
I guess, since you are editing a playground, you wanted the playground to show the value of theCard.name
here. That won't work for two reasons. First, playground execution stops at the first error. Second, you need to create a DeckOfCards
instance and then you can ask it for its theCard
.
class DeckOfCards {
static func makeDeckOfCards() {
blah blah blah
}
var deckOne = DeckOfCards.makeDeckOfCards()
var singleCard: Card
var theCard: (name: String, emoji: String, points: Int)
init() {
// Property initializers run before init runs,
// so deckOne is already initialized.
singleCard = deckOne[51]
theCard = singleCard.cardInfo
}
} // <-- This brace ends the declaration of DeckOfCards.
// AFTER ending the declaration of DeckOfCards, at the global scope:
let deck = DeckOfCards()
let card = deck.theCard
card.name
card.emoji
card.points
It looks there like the enum Rank
doesn't have a closing brace, so the brace that you think is closing Card
, is actually closing Rank
. Insert one after the closing brace of func cardsValue()
.
I think the main issues you're seeing above, Cannot use instance member 'singleCard' within property initializer; property initializers run before 'self' is available
are a direct result of not closing this enum properly. If you close this enum, then the }
after it will close Card
, which will push these declarations outside of Card
.
It can also be helpful, in Xcode, to select all your code and press Ctrl+I
, which will re-indent your code the way the compiler sees it. After doing that, if something is indented, you know it's inside something else.
Just a note: why can't Suit
be CaseIteratable
so you can do Suit.allCases.map { $0.rawValue }
?
You may also be interested in this example Swift Package: GitHub - apple/example-package-deckofplayingcards: Example package for use with the Swift Package Manager