0

The execution of this code is confusing me:

class RecipeListViewModel: ObservableObject {
    
    @Published var recipeList = [RecipeViewModel]()
    
    init(){

        RecipeRepository.$allRecipeVMs.map { recipes in
            recipes.map { recipe in
            recipe
            }
        }
        .assign(to: &$recipeList)
    }
}

My understanding was that SwiftUI publishers are uni-directional, meaning that when RecipeRepository.allRecipeVMs is modified recipeList is too. However, the behaviour I'm seeing is that When recipeList is updated, RecipeRepository.allRecipeVMs is also updated. I've tried to find documentation on this but can't seem to find anything.

Here is the RecipeViewModel class, not sure if it's useful:

class RecipeViewModel : Identifiable, ObservableObject, Hashable{
    
    var id = UUID().uuidString
    @Published var recipe: Recipe

    init(recipe: Recipe){

        self.recipe = recipe
    }
}
Spdollaz
  • 165
  • 10
  • Can you include a [mre] that demonstrates what you're describing? I'd like to see what's in `RecipeRepository` for example... I'm skeptical of `allRecipeVMs` – jnpdx Aug 01 '21 at 20:10
  • @jnpdx I'll work on creating a reproducible example, allRecipeVMs is [RecipeViewModel] though. – Spdollaz Aug 01 '21 at 20:16
  • That's a red flag that you have a `@Published` array of `ObservableObject` -- that won't work as you expect it to. – jnpdx Aug 01 '21 at 20:20

1 Answers1

2

It's not clear what "modifications" you are calling. @Published and SwiftUI views diff value types, whereas you've created an array of reference types. It will diff only when the instance of that object changes, not when the object itself fires its ObjectWillChange publisher.

Frankly, that's a pretty useful setup because you can have containers that distribute and manage dependencies in your app without causing the root view hierarchy to diff and rebuild constantly.

If you want some sort of two-way Delegate relationship, you can simply set a weak variable in the VMs to self.

Ryan
  • 1,252
  • 6
  • 15
  • Yes this is correct, I assumed this was something Combine was doing behind the scenes, but the RecipeRepository.allRecipeVMs array was updated when a recipeList child's property was altered as RecipeViewModel is a class (reference type). – Spdollaz Aug 02 '21 at 06:48
  • What's a bug somewhere might be a feature later :) Enjoy – Ryan Aug 02 '21 at 07:36