(SwiftUI) Как я могу получить доступ к совпадению, которое я нашел из одного массива в другом в ViewBuilder?

У меня два массива.

maschineItems: [MaschineItem]

maschines: [Maschine]

Оба объекта имеют свойство "имя".

В моем представлении я хочу проверить, существует ли имя maschineItem в массиве машин. Я хочу создать "светлый пузырь" для всех maschineItems, который существует в машинах, и "темный пузырь" для всех maschineItems, которого нет в машинах.

Вот мой код (который работает):

import SwiftUI
import Combine

struct OverviewView: View {
    
    @FetchRequest(fetchRequest: MaschineItem.getAllMaschines()) var maschineItems:FetchedResults<MaschineItem>
    @State var networkManager = NetworkManager()
    
    var body: some View {
        
        NavigationView{
            ScrollView{
                VStack(spacing: 30) {
                    ForEach(maschineItems) { maschineItem in
                        if NetworkManager.maschines.contains(where: {$0.name == maschineItem.name}) {
                            
                            BubbleView(locationText: "TEST LOCATION", textIo: "/", textnIo: "/", maschineItem: maschineItem, color: .dividerBackground, opacity: 0.25)
                            
                        }else {
                            BubbleView(locationText: "Unknown device", textIo: "/", textnIo: "/", maschineItem: maschineItem, color: .gray, opacity: 0.5)
                        }
                    }
                }
            }
            .navigationBarTitle("Übersicht", displayMode: .large)    
        }
    }

Теперь я хочу, чтобы Bubbles содержали информацию о машинах. Так что я должен инициализировать совпадение перед оператором if, не так ли? Но когда я это сделаю:

    var body: some View {
        
        NavigationView{
            ScrollView{
                VStack(spacing: 30) {
                    ForEach(maschineItems) { maschineItem in
                        if let maschines = NetworkManager.maschines.first(where: {$0.name == maschineItem.name}) {
                            
                            BubbleView(locationText: "\(maschines.location.building) / \(maschines.location.workcell)", textIo: "\(maschines.resultCountiO)", textnIo: "\(maschines.location.resultCountniO)", maschineItem: maschineItem, color: .dividerBackground, opacity: 0.5)
                            
                        }else {
                            BubbleView(locationText: "Unknown device", textIo: "/", textnIo: "/", maschineItem: maschineItem, color: .gray, opacity: 0.5)
                        }
                    }
                }
            }
            .navigationBarTitle("Übersicht", displayMode: .large)   
        }
    }

Я получаю следующую ошибку в строке оператора if:

Closure containing control flow statement cannot be used with function builder 'ViewBuilder'

Как я могу исправить эту проблему? Я много исследовал и нашел похожие темы, которые показали мне, что я должен использоватьarray.first(where: {})метод, но я не нашел ничего, что помогло бы мне с этой проблемой. И да, я попытался создать функцию, потому что в представлениях неправильная логика. Но когда я пишу все это в функции, возникает та же ошибка.

Я очень благодарен всем, кто пытается мне помочь. PS: Я немец, извините за английский:D

1 ответ

Я бы использовал вычисляемую переменную, которая предоставляет необходимые данные, избегая if let. В моем примере я добавил вычисляемую переменную (matchedMachines), который представляет собой массив кортежей. Первое значение в кортеже - этоMachineпример. Второе значение - этоBool это указывает на то, была ли найдена машина.

//
//  ContentView.swift
//  BubbleTest
//
//  Created by Paul Wilkinson on 26/6/20.
//

import SwiftUI

struct Machine: Identifiable {
    let id = UUID()
    let name: String
    let colour: String
}

struct ContentView: View {
    
    var machines = [Machine(name: "Bob", colour: "Grey"), Machine(name:"Susan",colour: "Purple"), Machine(name: "Mary", colour: "Red"), Machine(name: "Peter", colour: "Green")]
    
    var names = ["Bob","Mary"]
    
    var matchedMachines: [(Machine,Bool)]  {
        get {
            return machines.map { ($0, names.contains($0.name))
            }
        }
    }
    
    var body: some View {
        VStack(spacing:30) {
            ForEach(matchedMachines, id: \.0.id ) { machineTuple in
                BubbleView(bubbleColor: machineTuple.1 ? .blue:.gray) {
                    Text(machineTuple.0.name)
                    Text("Location: \(machineTuple.1 ? "Test Location" : "Location Unknown")")
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct BubbleView<Content: View>: View {
    let content: Content
    var bubbleColor: Color
    
    init(bubbleColor: Color, @ViewBuilder content: () -> Content) {
        self.bubbleColor = bubbleColor
        self.content = content()
    }
    
    var body: some View {
        VStack {
            content
        }
        .padding()
        .background(bubbleColor)
        .cornerRadius(12.0)
    }
    
}

struct BubbleView_Previews: PreviewProvider {
    static var previews: some View {
        BubbleView(bubbleColor: .blue) {
            Text("Hello world")
        }
    }
}
Другие вопросы по тегам