绑定集合中的项目

huangapple go评论40阅读模式
英文:

Binding an item within a collection

问题

以下是翻译好的部分:

查看以下代码

```swift
struct FruitDetailView: View {
    @EnvironmentObject var merchant: Merchant
    @State var item: Fruit

    var body: some View {
        VStack {
            Text(item.name)
            Button("Press Me") {
                item.name = "Watermelon"
                merchant.updateFruits(with: item)
            }
        }
    }
}

先前向用户显示了水果列表,当用户选择一个水果时,该选定的水果会传递到此详细视图,现在它作为 @State 受控属性存在。

Merchant 也会传递,因为我们想要保持商户的原始数组同步。同时更新水果和商户很繁琐。是否没有办法绑定水果,以便对其进行任何修改也会修改商户的水果数组中的条目?

这篇文章是基于我之前的帖子这里

在 Objective-C 的世界中,通过视图层次结构传递指针可以轻松更新以下三个项目。

@implementation Merchant

- (id)init {
    self = [super init];
    if (self) {
        
        Fruit *apple = [[Fruit alloc] initWithName: @"Apple"];
        Fruit *orange = [[Fruit alloc] initWithName: @"Orange"];
        Fruit *pear = [[Fruit alloc] initWithName: @"Pear"];
        
        self.fruits = @[apple, orange, pear];
    }
    return self;
}

@end

@interface FruitDetailViewController : UIViewController
@property (nonatomic, strong) Fruit *fruit;
@end

@implementation FruitDetailViewController

- (IBAction)buttonAction:(UIButton *)sender {
    self.fruit.name = @"Cherry";
}

请注意,我已经删除了代码部分中的 HTML 实体字符 (`"`) 并进行了翻译。

<details>
<summary>英文:</summary>

Looking at the following code

struct FruitDetailView: View {
@EnvironmentObject var merchant: Merchant
@State var item: Fruit

var body: some View {
    VStack {
        Text(item.name)
        Button(&quot;Press Me&quot;) {
            item.name = &quot;Watermelon&quot;
            merchant.updateFruits(with: item)
        }
    }
}

}


A list of fruits was previously displayed to the user and when the user selected a fruit, that selected fruit was passed to this detail view. Where it now exists as a @State controlled property. 

The merchant is also passed along because we want to keep the original array in sync. Updating both the fruit and the merchant is a pain. Is there no way to bind the fruit so that any modifications to it, also modifies the entry in the array of fruits on the merchant?

This post leads on from my previous post [here][1].

In the world of Objective-C the following three items could be updated by just passing a pointer through the view hierarchy.

@implementation Merchant

  • (id)init {
    self = [super init];
    if (self) {

      Fruit *apple = [[Fruit alloc] initWithName: @&quot;Apple&quot;];
      Fruit *orange = [[Fruit alloc] initWithName: @&quot;Orange&quot;];
      Fruit *pear = [[Fruit alloc] initWithName: @&quot;Pear&quot;];
    
      self.fruits = @[apple, orange, pear];
    

    }
    return self;
    }

@end

@interface FruitDetailViewController : UIViewController
@property (nonatomic, strong) Fruit * fruit;
@end

@implementation FruitDetailViewController

  • (IBAction)buttonAction:(UIButton *)sender {
    self.fruit.name = @"Cherry";
    }


  [1]: https://stackoverflow.com/q/75493273/9400730

</details>


# 答案1
**得分**: 0

正如我在你之前的问题中所说,有很多方法可以完成这些任务。

这里是另一种方法,只将 `Binding Fruit` 传递给 `FruitDetailView`。这真的取决于你想要做什么。

```swift
struct ContentView: View {
    @StateObject var merchant = Merchant()
    
    var body: some View {
        FruitsView().environmentObject(merchant)
    }
}

struct Fruit: Identifiable, Hashable {
    let id = UUID()
    var name: String
}

final class Merchant: ObservableObject {
    @Published var fruits = [Fruit(name: "Banana"), Fruit(name: "Apple")]
}

struct Selector: Identifiable {
    let id = UUID()
    var index: Int
}

struct FruitsView: View {
    @EnvironmentObject var merchant: Merchant
    @State var selection: Selector?
    
    var body: some View {
        VStack {
            ForEach(merchant.fruits.indices, id: \.self) { index in
                Button(merchant.fruits[index].name) {
                    selection = Selector(index: index)
                }.buttonStyle(.borderedProminent)
            }
        }
        .sheet(item: $selection) { selector in
            FruitDetailView(fruit: $merchant.fruits[selector.index])
        }
    }
}

struct FruitDetailView: View {
    @Binding var fruit: Fruit

    var body: some View {
        VStack {
            Text(fruit.name)
            Button("Press Me") {
                fruit.name = "Watermelon"
            }
        }
    }
}

编辑1:

这是另一种方法,使用 NavigationLink 转到 FruitDetailView 目标视图,而不是使用 sheet,只使用绑定:

struct FruitsView: View {
    @EnvironmentObject var merchant: Merchant

    var body: some View {
        NavigationStack {
            ForEach($merchant.fruits, id: \.id) { $fruit in
                NavigationLink(destination: FruitDetailView(fruit: $fruit)) {
                    Text(fruit.name)
                }
            }
        }
    }
}
英文:

Like I said in your previous question, there are many ways to do things.

Here is yet another way, where only a Binding Fruit
is passed to the FruitDetailView. It really depends what you want to do.

struct ContentView: View {
    @StateObject var merchant = Merchant()
    
    var body: some View {
        FruitsView().environmentObject(merchant)
    }
}

struct Fruit: Identifiable, Hashable {
    let id = UUID()
    var name: String
}

final class Merchant: ObservableObject {
    @Published var fruits = [Fruit(name: &quot;Banana&quot;), Fruit(name: &quot;Apple&quot;)]
}

struct Selector: Identifiable {
    let id = UUID()
    var index: Int
}

struct FruitsView: View {
    @EnvironmentObject var merchant: Merchant
    @State var selection: Selector?
    
    var body: some View {
        VStack {
            ForEach(merchant.fruits.indices, id: \.self) { index in
                Button(merchant.fruits[index].name) {
                    selection = Selector(index: index)
                }.buttonStyle(.borderedProminent)
            }
        }
        .sheet(item: $selection) { selector in
            FruitDetailView(fruit: $merchant.fruits[selector.index])
        }
    }
}

struct FruitDetailView: View {
    @Binding var fruit: Fruit

    var body: some View {
        VStack {
            Text(fruit.name)
            Button(&quot;Press Me&quot;) {
                fruit.name = &quot;Watermelon&quot;
            }
        }
    }
}

EDIT-1:

Here is another way using a NavigationLink to goto the FruitDetailView destination view,
instead of a sheet, using only bindings:

struct FruitsView: View {
    @EnvironmentObject var merchant: Merchant
    
    var body: some View {
        NavigationStack {
            ForEach($merchant.fruits, id: \.id) { $fruit in
                NavigationLink(destination: FruitDetailView(fruit: $fruit)) {
                    Text(fruit.name)
                }
            }
        }
    }
}

huangapple
  • 本文由 发表于 2023年2月19日 15:25:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定