That's the error I told you in a previous post.
@State var datum: Data
Replace with
var datum: Data
If tha works, don't forget to close the thread by marking this answer as correct. Otherwise, explain.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
This cannot compile. data is a constant that you try to modify.
let data = try Data(contentsOf: url)
let jsonDecoded = try JSONDecoder().decode([Data2].self, from: data)
data = jsonDecoded
The code I sent was:
let dataRead = try Data(contentsOf: url)
let jsonDecoded = try JSONDecoder().decode([Data2].self, from: dataRead)
data = jsonDecoded
With these changes, your code works OK.
Could you show the DataView code ?
Why is it data and not datum on line 28 of the first code ?
DataView(data: data[index])
With this simple change, it works here.
DataView(datum: data[index])
The screenshots show the change in String x
Did you change datum to a simple var and not a State var ?
Could you show the complete code, to see how Binding is used.
Logically,
@Binding var index: Int
should be in the ContentView
and the
@State var index = 0
in the other view
But I would need to check.
PS: don't forget to close the thread, eventually starting a new one where you reference this one.
Another point.
In DataView, index should not be a State variable.
Add a button in ContentView
VStack {
if showView && (index >= 0) && (index < data.count) {
DataView(datum: data[index])
}
Spacer()
HStack {
Text("Index: \(index) -> ")
Button("Next") {
index += 1
if index >= data.count { index = 0 }
}
}
}
You will see that text in DataView does not change
Text("DataView \(datum.str)")
always says DataView String 1
Now change DataView as follows to get it updated on index change by button press:
struct DataView: View {
/*@State*/ var datum: Data2
var body: some View {
Text("DataView \(datum.str)")
}
}
Note: I renamed data to datum for an array item, to differentiate from the array.
Now, I have to update my initial answer.
In fact, no need for showView and Dispatch (even though that made it work).
Just test index:
if (index < data.count) {
DataView(datum: data[index])
Without the index test, it crashes…
Swift/ContiguousArrayBuffer.swift:691: Fatal error: Index out of range
Reason is that DataView is not called immediately but only when State var data is populated by getData (then count changes) and has all its elements.
So the test has a similar effect as Dispatch to wait for data to be fetched.
It is a question of timing.
When onAppear returns, and DataView is called, the array is not yet populated, even though its count is already OK.
You have to wait for a short time in onAppear (0.01 s should be OK).
Here is the solution.
I had to rename Data to avoid the error above (Data is a Foundation type). I renamed to Data2
struct Data2: Decodable, Hashable {
let index: Int
let str: String
}
struct DataView: View {
@State var data: Data2
var body: some View {
Text("DataView \(data.str)")
}
}
struct ContentView: View {
@State var showView = false // To wait for array to be populated before we display the view
@State var data: [Data2]
@State var index: Int = 0
var body: some View {
VStack {
if showView {
DataView(data: data[index])
// Text("Hello \(data.count)") // To test if needed ; without async, data.count is 2. Seems OK, but…
// Text("Hello \(data.count) index \(index) \(data[0].str)") // but without async, it will crash, as data is not populated yet, even if count is already 2
}
}
.onAppear {
let filePath = Bundle.main.path(forResource: "data", ofType: "json")
let url = URL(fileURLWithPath: filePath!)
data = getData(url: url)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // <<-- THE KEY POINT 0.1 sec delay
self.showView = true
}
}
}
func getData(url: URL) -> [Data2] {
do {
let data = try Data(contentsOf: url)
let jsonDecoded = try JSONDecoder().decode([Data2].self, from: data)
return jsonDecoded
} catch let error as NSError {
print("Fail: \(error.localizedDescription)")
} catch {
print("Fail: \(error)")
}
return []
}
}
Credit: https://stackoverflow.com/questions/62355428/how-do-i-show-a-new-view-after-some-delay-amount-of-time-swiftui
A simpler option is to use an init:
struct ContentView: View {
@State var data: [Data2]
@State var index: Int = 0
init() {
let filePath = Bundle.main.path(forResource: "data", ofType: "json")
let url = URL(fileURLWithPath: filePath!)
// data = getData(url: url) // We cannot call getData in init
do {
let dataRead = try Data(contentsOf: url)
let jsonDecoded = try JSONDecoder().decode([Data2].self, from: dataRead)
data = jsonDecoded
return
} catch let error as NSError {
print("Fail: \(error.localizedDescription)")
} catch {
print("Fail: \(error)")
}
data = []
return
}
var body: some View {
VStack {
DataView(data: data[index])
}
}
}
Thanks.
But your code does not compile, with the following errors:
Does it compile for you ?
I succeeded moving Xcode 16.4, MacMini, MacOS 15.6 (24G84):
Here is the initial tabbar
I click on the tabor in the TabBarController
it turns blue
I click on icon of item 1 and start dragging (I had to take care to hold the mouse pressed). A position caret appears (I cannot screenshot the caret) and icon starts to move and the other to rearrange
I move the caret (and the icon) to the desired position) and drop it
The icons are reordered
If that's OK, don't forget to close the thread on this answer ; otherwise please explain where it fails.
As you noticed, there is another way to do it, by creating the segues in desired order.
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
Could you provide complete code as well as the json file ?
Is Data a structure you have defined ?
If it is an empty set, it should crash at:
DataView(data: data[index])
Do you get Fail messages ?
Problem is not in onAppear. I tested by replacing getData by a dummy call
.onAppear {
// let filePath = Bundle.main.path(forResource: "data", ofType: "json")
// let url = URL(fileURLWithPath: filePath!)
//
// data = getData(url: url)
data = [Data()]
}
And data DataView is not empty, as I could check with the following
struct DataView: View {
@State var data: Data
var body: some View {
Text("DataView \(data)")
}
}
So, it looks like you return from getData by line 29 and not 22.
So, could you change line 29, to return a custom single data to check ?
Did you try to set the placement, such as:
.searchable(text: $searchText, isPresented: $isSearchPresented, placement: .navigationBarDrawer, prompt: "Search...")
Topic:
UI Frameworks
SubTopic:
UIKit
Tags:
Welcome to the forum.
Could you show (screenshots) what you get and what you'd expect.
And please also post the complete code.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
@Ed Ford, for this useful clarification.
So that means there is no urgency to switch to Swift 6 mode, unless of course there are concurrency issues or we need specific Swift 6 feature ?
I understand however that it is wise to set concurrency checking at the max level, even in Swift 5 mode. Is it correct ?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
@eskimo
that was when testing with Swift6 and Xcode 16.4.
But after encapsulating the code using IBOutlet in
MainActor.assumeIsolated({
// using textField.text
})
I could remove the nonIsolated declaration for IBOutlet and get it working.
Unfortunately, I've not kept a version to reproduce the error.
In any case, I will not switch to Swift6 before using Xcode 26.
Topic:
Programming Languages
SubTopic:
Swift
Tags:
Logically, users would receive an error message from your app if backend is off.
In any case, if you don't update the app for 3 years, it will be removed automatically.
May be the best is just to wait ?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
No feedback. Closing the thread.
Topic:
Developer Tools & Services
SubTopic:
Apple Developer Program
Tags: