Your Second iOS and SwiftUI App · Binding | raywenderlich.com

delete the last item
then click any item
will crash
index out of range

@ys_xs Do you still have issues with this?

using sample end code provided here in this page
still have the same problem

Hi! Yes in this scenario the app crashes…
I have another remark, if I tap a task and then go back, I can’t open it again… ^^’

I followed every step of the whole ‘Your Second iOS and SwiftUI App’ and even re-created a new project, but every time I reach this episode, i get an error. When I remove the .indices from taskStore.tasks in contentview, i get an error saying "Cannot convert value of type ‘[Task]’ to expected argument type ‘Range’ ". I have tried to figure this out myself, and even after recreating the project, I still got the same result.
Is anyone else having the same issue? Am i possibly missing something? Anything you have will help, thanks!

1 Like

I recommend using Git to find the exact differences between versions of a project. Are you familiar with it? If not, upload your version and I’ll let you know what it has to say!

Also recommended!
https://www.raywenderlich.com/4418-beginning-git
https://www.raywenderlich.com/4289-mastering-git

Hi. Thanks as always for the thorough walkthrough in every video! Though, I seem to be having a difficulty in understanding the last two episode, and I was wondering if I’m the only person and therefore need to go over them again to understand the concepts before I go any further. Thanks!

Feel free to continue on with this course, and see if you can get by with incomplete understanding. We all have incomplete understanding of these topics, after all! :smile_cat: They’re too huge to know everything about. The key is to keep practicing and building knowledge up incrementally.

If the rest of this course gives you trouble, then try a later one in the learning path, and come back to this one after a break. It could help!

Hi, I had the same issue. I believe when you copied the extension folders, you had selected “Create folder references” instead of “Create groups”. With “Create folder references”, the folder icon is in blue and not yellow as it should be. Hope this helps!

2 Likes

@jessycatterwaul I’m very confused as to when to use bindings, and when to use classes.

In the RowView file, we accept a @Binding, and pass that down to the TaskEditingView.

However, we have another view that we are passing down the entire “task store” class to, but not using a binding (not even sure that’s possible).

When we append to the task array, it all works fine and updates the state, even though we’re not using a binding.

How can NewTaskView edit the “task store” without needing a binding, but when I tried to make the “task” struct a class, and pass that down to the TaskEditingView, and modify it’s name property, the changes would not be reflected at all.

I’m seriously confused as to when and how we should use @Binding vs Classes and why classes sometimes work as references in SwiftUI and sometimes don’t.

Can anyone explain or follow up with me?

I’m very confused as to when to use bindings, and when to use classes.

That’s reasonable! They can solve the same problems. So the choice isn’t a matter of technical restrictions, but architectural design.

Who owns the model? Can you realistically say that a view does? If so, State+Bindings are how to represent that.

If, like in this app, the model really belongs to an ancestor of multiple views, and that thing itself is not a view (e.g. it’s the “app” itself), then an observable object is a better representation.

(not even sure that’s possible).

It’s possible. Using Binding on a reference type will allow you to reassign the reference, for all views. Generally, that’s not going to be necessary, or a good idea! Reassigning references for other instances makes for hard to follow code, and is normally a more complex way of going about a task than it needs to be.

How can NewTaskView edit the “task store” without needing a binding…

ObservableObject+Published+ObservedObject.

…but when I tried to make the “task” struct a class, and pass that down to the TaskEditingView, and modify it’s name property, the changes would not be reflected at all.

Building with Xcode 11.4, the changes are reflected, for me. Like I went over in the Observable Objects episode, don’t try to make predictions about whether the changes in the model are going to be reflected in the UI, without a guarantee. Otherwise, the results will change unexpectedly.

1 Like

@jessycatterwaul Thanks for your prompt response! You clarified a lot for me but I am still confused on my experiment to pass down a “task class” and edit it. When I do this in the “RowView.swift file” like so:

	struct RowView: View {

	var task: Task

	var body: some View {
		Button(action: { self.task.name = "This new name should be shown but is not!" }) {
			Text(task.name).strikethrough(task.completed)
		}


	}
}

The new name is not updated in the list. It will be however, if I open the the NewTaskView, which forces a re-render.

I don’t understand how ObservedObject can listen to the appending of the array (without a binding), but cannot listen to the change of a reference type’s property in that array.

Are you using the 11.4 beta? That’s not the behavior I get. Only the new rows re-render.

In order to see what you’re seeing, I need to change the Identifiable behavior of Task. Again, this is all subject to change. Don’t put any faith in SwiftUI magically working, when there are ways to force it to work.

Arrays are value types. @Published is just a shortcut to calling objectWillChange in the array’s willSet observer (with some async magic to make it more like didSet).

@jessycatterwaul Maybe this is because I’m displaying RowViews like this?

ForEach(
  Array( taskStore.tasks.enumerated() ),
  id: \.element.id
) { index, _ in
  RowView(task: self.taskStore.tasks[index])
}

I wouldn’t think that would result in anything different. You’re still using the same id. I don’t know what the rest of your project looks exactly like, though.

@jessycatterwaul Maybe my Task.swift is the problem?


import Foundation

class Task: Identifiable {
	let id = UUID()

	var name: String
	var completed: Bool = false

	init(name: String) {
		self.name = name
	}
}

I just want to understand why changing a Task class doesn’t cause the row to be updated, but appending to the task list does?

I think I may understand why it’s not updating when the class gets updated. As this StackOverflow post explains: Why is an ObservedObject array not updated in my SwiftUI application? - Stack Overflow.

“Since classes are references the array remains unchanged and so nothing is emitted by the subject.”

Does this sound correct to you?

Yes! :+1:

That’s why I mentioned above that Swift Arrays are value types. I didn’t realize that you didn’t know about what you found at that link, which is the converse of that. If you reassign a reference in an Array, that’s a mutation of the Array. But if you mutate any property of a reference in an Array, it’s not.

More on this here. Let me know if you think there’s anything missing that we don’t cover, which would have helped you. (I realize the third link is after this course, in the learning path.)

1 Like

I have a question to a bug I found.

When I add a Task and after adding immediately I try to use the Edit Button, the Rows don’t change to the edit mode. A weird fading happens.

What could be the reason? It happens also with the code for this course if I download it.

Thank you

Hi!

I’d like to see a video of this “weird fading”. As you can see in the comments for most of the videos, all of us are having an issue after adding a task, but I haven’t heard about fading yet!