SwiftUI - Как включить все логические значения в CoreData - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть база данных с несколькими объектами с логическим значением в качестве атрибута. Я ищу функцию для инвертирования всех логических объектов при нажатии кнопки. Я пробовал эту функцию, но несколько ошибок отображаются как (Значение типа 'Bool' не имеет члена 'индексы'):

struct ViewList: View {
  @Environment(\.managedObjectContext) var context
  @State var newName: String = ""
  @FetchRequest(
      entity: Product.entity(),
      sortDescriptors: [NSSortDescriptor(keyPath: \Product.name, ascending: true)]
  ) var list: FetchedResults<Product>

  var body: some View {
      VStack {
          HStack {
                TextField("I insert the name of the product", text: $newName)
              Button(action: { self.add()
                               self.newName = ""
              })
              { Image(systemName: "plus") }
          }
          List {
              ForEach(list, id: \.self) {
                  product in ViewItem(product: product)
              }
          }
      }
  }
  public func add() {
      let newProduct = Product(context: context)
      newProduct.name = newName
      do {
          try context.save()
      } catch {
          print(error)
      }
  }
}                       


struct ViewItem: View {
  @State var product: Product
  @State var refresh: Bool = false

  var body: some View {
      NavigationLink(destination: ViewDetail(product: product, refresh: $refresh)) {
          HStack(alignment: .top) {
              Button( action: {
                  self.clean()
                  self.product.isSelected.toggle()
              }) {
                  if self.product.isSelected == true {
                      Image(systemName: "checkmark")
                  } else {
                      Image(systemName: "checkmark").colorInvert()
                  }
              }
              VStack() {
                  Text(product.name)
                  if product.password != "" {
                      Text("Password : " + product.password)
                  }
                  Text(String(refresh)).hidden()
              }
          }
      }
      .onAppear {
          self.refresh = false
      }
  }

}

Я думал об этом, но Я не знаю, как go об этом ...

func clean() {
    for( index ) in self.product.isSelected.indices {
        self.product[index]isSelected = false
    }
}

1 Ответ

0 голосов
/ 24 апреля 2020

Вам необходимо создать запрос, чтобы изменить состояние флага isSelected. Эту логику c лучше держать вне системы просмотра, чтобы вы могли использовать ее где угодно

Вы создаете SelectionHandler

import CoreData

class SelectionHandler {

    func clearSelection(in context: NSManagedObjectContext) {
        for item in currentSelected(in: context) {
            item.isSelected = false
        }
    }

    func selectProduct(_ product: Product) {
        guard let context = product.managedObjectContext else {
            assertionFailure("broken !")
            return
        }

        clearSelection(in: context)
        product.isSelected = true
    }

    func currentSelected(in context: NSManagedObjectContext) -> [Product] {
        let request = NSFetchRequest<Product>(entityName: Product.entity().name!)
        let predicate = NSPredicate(format: "isSelected == YES")
        request.predicate = predicate

        do {
            let result = try context.fetch(request)
            return result
        } catch  {
            print("fetch error =",error)
            return []
        }

    }

}

, который затем можно использовать для выбора желаемого продукта.

SelectionHandler().selectProduct(product)

В нынешнем виде NavigationLink ничего не будет делать, поскольку родительский список не содержится в NavigationView, поэтому вам нужно изменить тело ViewList

var body: some View {
    NavigationView {
        VStack {
            HStack {
                TextField("Create product with name", text: $newName)
                Button(action: {
                    self.add()
                    self.newName = ""
                })
                { Image(systemName: "plus") }
            }
            .padding()
            List {
                ForEach(list, id: \.self) { product in
                    ViewItem(product: product)
                }
            }
        }
    }
}

, а в ViewItem Product должно быть ObservedObject, чтобы изменения обнаруживались в управляемом объекте.

struct ViewItem: View {

    @ObservedObject var product: Product
    @State var refresh: Bool = false

    var checkmarkImage: some View {
        return Group {
            if self.product.isSelected {
                Image(systemName: "checkmark")
            } else {
                Image(systemName: "checkmark").colorInvert()
            }
        }
    }

    var body: some View {
        NavigationLink(destination: ViewDetail(product: product, refresh: $refresh)) {
            HStack {
                checkmarkImage
                Text(product.name ?? "wat")
            }
        }
    }
}

Оригинал Button не будет играть с NavigationLink, но вы можете просто применить выбор к onAppear в ViewDetail

struct ViewDetail: View {

    @ObservedObject var product: Product
    @Binding var refresh: Bool

    var body: some View {
        VStack {
            Text("Hello, World!")
            Text("Product is \(product.name ?? "wat")")
        }
        .onAppear {
            SelectionHandler().selectProduct(self.product)
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...