I've been at it for more than 8h refactoring the code over and over again and I can't get it to work, I have this in my view:
ForEach(allWalletsData.walletList) { walletKey in
WalletStackView(user: user, walletAddress: walletKey)
}
and it complains saying: value of type 'String' has no member 'walletList'
if I try another combination like:
ForEach(allWalletsData.walletList) { walletKey in
WalletStackView(user: user, walletAddress: walletKey)
}
it says: referencing initializer 'init(_:content:)' on 'ForEach' requires that 'String' conform to 'Identifiable'
The data comes from a Publisher:
@Published var allWalletsData: AllWalletsData = AllWalletsData(walletList: [], walletsData: [:], combinedWalletTokensQuotesFormatted: "")
In my model I've wrote it 1000 different ways and still... doesn't work.
The information in it cannot be static, as I refresh the API, the data will change.
This is the model I've tried:
struct AllWalletsData: Decodable, Encodable {
init(walletList: [String], walletsData: OrderedDictionary<String, WalletInformation>, combinedWalletTokensQuotesFormatted: String) {
self.walletList = walletList
self.walletsData = walletsData
self.combinedWalletTokensQuotesFormatted = combinedWalletTokensQuotesFormatted
}
let walletList: [String]
let walletsData: OrderedDictionary<String, WalletInformation>
let combinedWalletTokensQuotesFormatted: String
}
extension AllWalletsData: Hashable, Identifiable {
var id: [String] { walletList }
func hash(into hasher: inout Hasher) {
hasher.combine(combinedWalletTokensQuotesFormatted)
}
static func ==(lhs: AllWalletsData, rhs: AllWalletsData) -> Bool {
if lhs.combinedWalletTokensQuotesFormatted != rhs.combinedWalletTokensQuotesFormatted {
return false
}
return true
}
}
I've burned out at this point trying to find out what's happening, does anyone know what's going on?
EDIT:
Here's the second part of the model that contains the data using in the ForEach:
struct WalletInformation: Decodable, Encodable {
init(wallet: Wallet, chainsInfo: [ChainReCalculatedData], allChainsTotalBalanceValue: String) {
self.wallet = wallet
self.chainsInfo = chainsInfo
self.combinedChainsTokensQuotesFormatted = allChainsTotalBalanceValue
}
let wallet: Wallet
let chainsInfo: [ChainReCalculatedData]
// Combined chain balances
let combinedChainsTokensQuotesFormatted: String
}
extension WalletInformation: Hashable, Identifiable {
var id: String { wallet.address }
public func hash(into hasher: inout Hasher) {
hasher.combine(wallet)
hasher.combine(chainsInfo)
hasher.combine(combinedChainsTokensQuotesFormatted)
}
public static func ==(lhs: WalletInformation, rhs: WalletInformation) -> Bool {
if lhs.wallet != rhs.wallet {
return false
}
if lhs.chainsInfo != rhs.chainsInfo {
return false
}
if lhs.combinedChainsTokensQuotesFormatted != rhs.combinedChainsTokensQuotesFormatted {
return false
}
return true
}
}
CodePudding user response:
Instead of making AllWalletsData Identifiable, you need to make the individual items of your collection Identifiable or Hashable, or provide an ID.
Your collection is allWalletsData.walletList -- according to your model, this is of type [String]. So, one option is:
ForEach(allWalletsData.walletList, id: \.self) { walletKey in
WalletStackView(user: user, walletAddress: walletKey)
}
That tells SwiftUI to use the String as the id for each item (which looks like what you were trying to accomplish by doing var id: [String] { walletList }.
Beware that if walletAddress doesn't contain truly unique elements, this (using id: \.self) can lead to unpredictable results. The other route to go would be defining a model for your wallet that had truly unique ids (like a UUID).
Update, based on comments:
It sounds like instead of trying to store separate arrays of keys and dictionaries of your data, you should just have an array of your models. Something like:
struct WalletInformation : Identifiable, Codable {
var id = //...
//other properties
}
struct AllWalletsData: Decodable, Encodable {
var walletList : [WalletInformation]
}
//and your ForEach:
ForEach(allWalletsData.walletList) { wallet in
WalletStackView(user: user, wallet: wallet)
}
