swiftdata - Create state array from query results in SwiftUI view using results of a Swift data query - Stack Overflow
- c - Solaris 10 make Error code 1 Fatal Error when trying to build python 2.7.16 - Stack Overflow 推荐度:
- javascript - How to dismiss a phonegap notification programmatically - Stack Overflow 推荐度:
- javascript - Get the JSON objects that are not present in another array - Stack Overflow 推荐度:
- javascript - VS 2015 Angular 2 import modules cannot be resolved - Stack Overflow 推荐度:
- javascript - Type 'undefined' is not assignable to type 'menuItemProps[]' - Stack Overflow 推荐度:
- 相关推荐
I have the following view which works as I want with an array of objects and now I want to refactor it so that the array of objects is created by iterating over the results of a Swift data query.
The reason for this is because I need to access the functions in the observable stopwatch object from the Edit view. I could create the Player objects in the ForEach by passing the model and stopwatch objects to a child view, however, I am then unable to access the required functions in stopwatch object from the parent view when in Edit mode.
To summarise functionality:
- View presents a list of players, each with an instance of the stopwatch
- Swipe actions can start/stop the stopwatch for individual players
- Edit mode can be used for starting the stopwatch for multiple players
struct ContentView: View {
@State private var editMode = EditMode.inactive
@State private var selectedPlayers: Set<Player.ID> = []
@State var players = [
Player(name: "Player 1", stopwatch: Stopwatch(timeElapsed: 0)),
Player(name: "Player 2", stopwatch: Stopwatch(timeElapsed: 0)),
Player(name: "Player 3", stopwatch: Stopwatch(timeElapsed: 0)),
]
var body: some View {
NavigationStack {
VStack {
List(selection: $selectedPlayers) {
ForEach(players) { player in
HStack {
Text(player.name)
Spacer()
StopwatchView(stopwatch: player.stopwatch)
.swipeActions(edge: .leading) {
Button(action: {
player.stopwatch.start()
}) {
Image(systemName: "play.circle.fill")
}
}
.tint(.green)
.swipeActions(edge: .trailing) {
Button(action: {
player.stopwatch.stop()
}) {
Image(systemName: "stop.circle.fill")
}
}
.tint(.red)
}
}
}
}
.navigationTitle("Players")
.toolbar {
if editMode.isEditing == true && !selectedPlayers.isEmpty {
Button(
action: {
selectedPlayers.forEach { playerId in
let playerInstance = players.filter {
$0.id == playerId
}
playerInstance.first?.stopwatch.start()
}
}) {
Image(systemName: "play.circle.fill")
}
}
EditButton()
}
.environment(\.editMode, $editMode)
}
}
}
Example model:
@Model
class GamePlayer: Identifiable {
var id: String
var name: String
var gameTime: Double
@Transient var timer: Stopwatch = Stopwatch()
init(id: String = UUID().uuidString, name: String, gameTime: Double = 0) {
self.id = id
self.name = name
self.gameTime = gameTime
}
}
extension GamePlayer {
static var defaults: [GamePlayer] {
[
GamePlayer(name: "Jake"),
GamePlayer(name: "Jen"),
GamePlayer(name: "Ben"),
GamePlayer(name: "Sam"),
GamePlayer(name: "Tim"),
]
}
}
In content view, I need to generate an array of Player objects for each object in the GamePlayer model, with a stopwatch.
@Environment(\.modelContext) var modelContext
@Query() var gamePlayer: [GamePlayer]
So my question is, how do I iterate over the query results to create the required array of Player objects?
It would also be good to know if I'm approaching this in the correct way. I'm only a couple of months into learning Swift so please go easy on my code.
I have the following view which works as I want with an array of objects and now I want to refactor it so that the array of objects is created by iterating over the results of a Swift data query.
The reason for this is because I need to access the functions in the observable stopwatch object from the Edit view. I could create the Player objects in the ForEach by passing the model and stopwatch objects to a child view, however, I am then unable to access the required functions in stopwatch object from the parent view when in Edit mode.
To summarise functionality:
- View presents a list of players, each with an instance of the stopwatch
- Swipe actions can start/stop the stopwatch for individual players
- Edit mode can be used for starting the stopwatch for multiple players
struct ContentView: View {
@State private var editMode = EditMode.inactive
@State private var selectedPlayers: Set<Player.ID> = []
@State var players = [
Player(name: "Player 1", stopwatch: Stopwatch(timeElapsed: 0)),
Player(name: "Player 2", stopwatch: Stopwatch(timeElapsed: 0)),
Player(name: "Player 3", stopwatch: Stopwatch(timeElapsed: 0)),
]
var body: some View {
NavigationStack {
VStack {
List(selection: $selectedPlayers) {
ForEach(players) { player in
HStack {
Text(player.name)
Spacer()
StopwatchView(stopwatch: player.stopwatch)
.swipeActions(edge: .leading) {
Button(action: {
player.stopwatch.start()
}) {
Image(systemName: "play.circle.fill")
}
}
.tint(.green)
.swipeActions(edge: .trailing) {
Button(action: {
player.stopwatch.stop()
}) {
Image(systemName: "stop.circle.fill")
}
}
.tint(.red)
}
}
}
}
.navigationTitle("Players")
.toolbar {
if editMode.isEditing == true && !selectedPlayers.isEmpty {
Button(
action: {
selectedPlayers.forEach { playerId in
let playerInstance = players.filter {
$0.id == playerId
}
playerInstance.first?.stopwatch.start()
}
}) {
Image(systemName: "play.circle.fill")
}
}
EditButton()
}
.environment(\.editMode, $editMode)
}
}
}
Example model:
@Model
class GamePlayer: Identifiable {
var id: String
var name: String
var gameTime: Double
@Transient var timer: Stopwatch = Stopwatch()
init(id: String = UUID().uuidString, name: String, gameTime: Double = 0) {
self.id = id
self.name = name
self.gameTime = gameTime
}
}
extension GamePlayer {
static var defaults: [GamePlayer] {
[
GamePlayer(name: "Jake"),
GamePlayer(name: "Jen"),
GamePlayer(name: "Ben"),
GamePlayer(name: "Sam"),
GamePlayer(name: "Tim"),
]
}
}
In content view, I need to generate an array of Player objects for each object in the GamePlayer model, with a stopwatch.
@Environment(\.modelContext) var modelContext
@Query() var gamePlayer: [GamePlayer]
So my question is, how do I iterate over the query results to create the required array of Player objects?
It would also be good to know if I'm approaching this in the correct way. I'm only a couple of months into learning Swift so please go easy on my code.
Share Improve this question edited 18 hours ago Lymedo asked 22 hours ago LymedoLymedo 60810 silver badges23 bronze badges 5 |1 Answer
Reset to default 1Make the players
property into a @Query
property instead
@Query private var players: [GamePlayer]
and then update the Stopwatch for each player in onAppear
.onAppear {
players.forEach { $0.stopwatch.gameTime = $0.gameTime }
}
You could also consider making the stopwatch
property optional and assign a new instance in onAppear
instead if it doesn't make sense for a GamePlayer
object to always have one assigned.
.onAppear {
players.forEach { $0.stopwatch = Stopwatch(gameTime: $0.gameTime) }
}
- powershell - Questionable output while iterating over an array of arrays - Stack Overflow
- javascript - How to delete content from content-editable field on facebookmessenger.com? - Stack Overflow
- macos - Can't access UI "section" in AppleScript - Stack Overflow
- sql - Ranking query records in specific order - Stack Overflow
- linker - Appending to an ELF file - Cortex MGCC - Stack Overflow
- Download Password Protected File from OneDrive with CURL - Stack Overflow
- nim lang - How to parse a JSON file in Nim using the standard library? - Stack Overflow
- flutter - Retrieving tokens from aad_b2c_webview - Stack Overflow
- oauth 2.0 - how Can we add group roles claim in okta access token or id token - Stack Overflow
- Meta Graph API Post engagement - Stack Overflow
- c# - Trouble when setting up Serilog in ASP.NET Core Web API - Stack Overflow
- wordpress - XML Reader Not Found in cPANEL php v8.3 - Stack Overflow
- python - Galaga game not running due to an empty range - Stack Overflow
- mapping - How to display drawdown contours calculated with the Theis equation to display on an interactive map in Dash with Pyth
- netcdf4 - Issue with renaming netCDF dimensions with NCO's ncrename - Stack Overflow
- Is it possible to determine if the Julia JIT will return a heap allocated or stack allocated return value from a function call?
- javascript - How can I create hyperlinkOrPicture column types on SharePoint Lists with Microsoft Graph API or Sharepoint API? -
GamePlayer
andPlayer
? Why not add the stopwatch (or whatever else you need) to the SwiftData model? They can be@Transient
if you SwiftData to ignore them. – Sweeper Commented 21 hours agogameTime
in the code in the question. Please edit your question to clarify what your real code looks like. – Sweeper Commented 18 hours ago