SwiftUI Picker多个错误,核心数据,布局

时间:2019-11-17 01:37:18

标签: core-data swiftui

我一直在努力地使多个Pickers处于Form布局中以在SwiftUI中工作。

作为测试,我创建了一个简单的视图,其中包含一些文本标签,一些TextField和 两个选择器。这是一个核心数据应用程序。首先创建一个 数组。第二个是直接从Core Data中填充的。似乎没有 功能或错误上的差异。

该功能似乎正在运行,但是我收到了看起来像真实错误的这些错误 问题。单击选择器后,我将毫无问题地过渡到选择器列表。 单击列表项后,选择器列表将被关闭,并返回到ContentView 选择器中列出的适当选项。但是,在两种选择器情况下, 这些错误:

1。 ForEach,Int,Text>计数(10)!=初始计数(1)。 ForEach(_:content:)仅应用于恒定数据。而是使数据符合Identifiable或使用ForEach(_:id:content:)并提供明确的id

2。 [TableView]仅警告一次:通知UITableView布置其可见单元格和其他内容,而不必放在视图层次结构中(表视图或其父视图之一尚未添加到窗口)。这可能会迫使表视图内的视图加载和执行布局而没有准确的信息,而且还会产生更多的琐碎问题,从而导致错误。

这是主视图:

struct ContentView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(fetchRequest: Clinic.getAllClinics()) var clinics: FetchedResults<Clinic>

    @State var nameArray = Clinic.makeClinicNameArray()

    @State private var selectArrayItem = 0
    @State private var selectCoreDataItem = 0
    @State private var tfOne = "TextField One"
    @State private var tfTwo = "TextField Two"
    @State private var tfThree = "TextField Three"
    @State private var tfFour = "TextField Four"

    var body: some View {
        NavigationView {

            Form {

            //I have include groups because in the real app I have many more than
            //ten views in the parent view
                Group {
                    TextField("enter a value for tfOne", text: $tfOne).foregroundColor(.blue)
                }

                Section(header: Text("From Generated Array:"), footer: Text("Section End")) {
                    Picker(selection: $selectArrayItem, label: Text("Choose Array Clinic")) {
                        ForEach(0 ..< nameArray.count) {
                            Text(self.nameArray[$0])
                        }
                    }
                    .foregroundColor(.red)

                    Picker(selection: $selectCoreDataItem, label: Text("Choose Core Data Clinic")) {
                        ForEach(0 ..< clinics.count) {
                            Text("\(self.clinics[$0].name ?? "Nameless")")
                        }
                    }.foregroundColor(.orange)

                    Text("$selectArrayItem is \(selectArrayItem)")
                    Text("item name is \(self.nameArray[selectArrayItem])")
                }//section 1

                Group {
                    TextField("enter a value for tfTwo", text: $tfTwo).foregroundColor(.blue)
                    TextField("enter a value for tfThree", text: $tfThree).foregroundColor(.blue)
                }

                Section(header: Text("From Core Data:"), footer: Text("Section End")) {
                    Text("$selectCoreDataItem is \(selectCoreDataItem)")
                    Text("item name is \(self.clinics[selectCoreDataItem].name ?? "Nameless")")
                }//section two

                TextField("enter a value for tfFour", text: $tfFour).foregroundColor(.blue)

            }//Form
            .navigationBarTitle(Text("Spinners"))

        }//nav view
    }
} 

在阅读了许多SO帖子和Apple文档之后,我仍然没有找到任何相关的内容 根据我的情况。

作为参考,我在SO 58784465中发布了类似的问题。在这种情况下, 从ScrollView到Form的外部包装器可以工作-有点-但仅适用于 选择器。添加第二个选择器破坏了整个视图和数据处理。以上 应用就是为了解决这些问题而创建的。

enter image description here

和ManagedObject:

public class Clinic : NSManagedObject, Identifiable {
    @NSManaged public var myID: UUID
    @NSManaged public var name: String?
    @NSManaged public var comment: String?
    @NSManaged public var isShown: Bool
}

extension Clinic {

    static func getAllClinics() -> NSFetchRequest<Clinic> {
        let request: NSFetchRequest<Clinic> = Clinic.fetchRequest() as! NSFetchRequest<Clinic>
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        request.sortDescriptors = [sortDescriptor]
        return request
    }

    static func makeClinicArray() -> [Clinic] {
        let kAppDelegate = UIApplication.shared.delegate as! AppDelegate
        let request: NSFetchRequest<Clinic> = Clinic.fetchRequest() as! NSFetchRequest<Clinic>
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        request.sortDescriptors = [sortDescriptor]

        do {
            let results = try kAppDelegate.persistentContainer.viewContext.fetch(request)
            return results
        } catch {
            print("error retrieving filtered picker1s")
        }
        return [Clinic]()
    }

    static func makeClinicNameArray() -> [String] {

        var returnedArray = [String]()
        let kAppDelegate = UIApplication.shared.delegate as! AppDelegate
        let request: NSFetchRequest<Clinic> = Clinic.fetchRequest() as! NSFetchRequest<Clinic>
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        request.sortDescriptors = [sortDescriptor]

        do {
            let results = try kAppDelegate.persistentContainer.viewContext.fetch(request)
            for result in results {
                returnedArray.append(result.name ?? "Nameless")
            }
        } catch {
            print("error retrieving filtered picker1s")
        }
        return returnedArray
    }

}

Xcode版本11.2.1(11B500)将提供任何指导。

编辑:在SceneDelegate中添加核心数据设置(AppDelegate代码严格库存。

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)

        let tabby = TabBar().environment(\.managedObjectContext, managedObjectContext)

        window.rootViewController = UIHostingController(rootView: tabby)
        self.window = window
        window.makeKeyAndVisible()
    }
}

非常简单的TabBar: struct TabBar:查看{

@Environment(\.managedObjectContext) var managedObjectContext
@State private var selectionValue = 1

var body: some View {
    TabView(selection : $selectionValue) {
        ContentView().tabItem ({
            Image(systemName: "house")
            Text("Home")
        })
        .tag(1)

        Utilities().tabItem ({
            Image(systemName: "hammer")
            Text("Utilities")
        })
        .tag(2)

        StartView().tabItem ({
            Image(systemName: "forward.fill")
            Text("Start")
        })
        .tag(3)
    }
}

}

1 个答案:

答案 0 :(得分:1)

#1的答案几乎可以肯定是您需要将ForEach初始化程序与id参数一起使用,并且selection的类型必须与{{ 1}}。

例如,

id

之所以可以工作,是因为@State private var selectArrayItem = 0 ... Picker(selection: $selectArrayItem, label: Text("Choose Array Clinic")) { ForEach(0 ..< nameArray.count, id: \.self) { Text(self.nameArray[$0]) } } selectArrayItem都是id,或者

Int

将起作用,因为@State private var selectName = "" ... Picker(selection: $selectArrayItem, label: Text("Choose Array Clinic")) { ForEach(nameArray, id: \.self) { Text($0) } } selectName都是id

对于#2,我几乎肯定是SwiftUI中的一个错误。当我单击“选择阵列诊所”行时,看到打印出上述错误消息,并显示了诊所列表。您会注意到,将选择器视图推入导航堆栈后,表行在出现后不久会略微跳转。

错误消息和视觉跳转使我推测,SwiftUI在尝试从技术上讲是导航堆栈的一部分之前试图对行进行布局,该行会打印错误,然后在添加错误后立即添加视图行偏移量重新计算,导致跳跃。这些都不在您的控制范围内,而是通过最简单的String / Form演示代码来实现的。最好的办法是将report it作为一个错误并立即使用它。除了视觉跳跃之外,目前看来没有任何功能性问题。