我一直在努力地使多个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的外部包装器可以工作-有点-但仅适用于 选择器。添加第二个选择器破坏了整个视图和数据处理。以上 应用就是为了解决这些问题而创建的。
和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)
}
}
}
答案 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作为一个错误并立即使用它。除了视觉跳跃之外,目前看来没有任何功能性问题。