我是SwiftUI的新手,部分是Swift的新手,所以希望有人可以对我公然缺少的东西有所了解。麻烦代码了!我还没有机会重构。
我正在使用@FetchRequest
属性包装器,从Memories
模型中拉回所有CoreData
的列表,并在其上定义了NSFetchRequest<Memory>
方法,从NSManagedObject
。
当我通过FetchRequest<Memory>
遍历SwiftUI中ForEach
的结果时,它将NSManagedObject
的一个实例返回到循环变量中,而不是Memory
,并且因此,对于以下SwiftUI类,显示错误:Value of type 'NSManagedObject' has no member 'createdAt'
:
import SwiftUI
struct MemoryView: View {
@Environment(
\.managedObjectContext
) var managedObjectContext
@FetchRequest(
fetchRequest: Memory.allMemories()
) var allMemories: FetchedResults<Memory>
@State private var newMemory = ""
var body: some View {
NavigationView {
List {
Section(header: Text("What's on your mind?")) {
HStack {
TextField("New memory", text: self.$newMemory)
Button(action: {
let memory = Memory(context: self.managedObjectContext)
memory.title = self.newMemory
memory.createdAt = Date()
do {
try self.managedObjectContext.save()
} catch {
print(error)
}
self.newMemory = ""
}) {
Image(systemName: "plus.circle.fill")
.foregroundColor(.green)
.imageScale(.large)
}
}
}
.font(.headline)
Section(header: Text("My Memories")) {
ForEach(self.allMemories) { memoryItem in
MemoryRow(title: memoryItem.title, createdAt: memoryItem.createdAt)
// /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\
// >>> Error:
// >>> Value of type 'NSManagedObject' has no member 'createdAt'
}
}
}
.navigationBarTitle(Text("Memories"))
.navigationBarItems(trailing: EditButton())
}
}
}
struct MemoryView_Previews: PreviewProvider {
static var previews: some View {
MemoryView()
}
}
作为参考,有问题的Memory
模型如下:
import Foundation
import CoreData
import CoreLocation
// Define the CoreData Object Model.
// Ensuring that this class name matches
// the entity model name.
public class Memory: NSManagedObject, Identifiable {
@NSManaged public var title: String?
@NSManaged public var body: String?
@NSManaged public var latitude: Double
@NSManaged public var longitude: Double
@NSManaged public var createdAt: Date?
@NSManaged public var updatedAt: Date?
// @NSManaged public var type: Type?
// @NSManaged public var tags: [Tags]?
}
// Create an extension in which to place things out of the context
// of the initial class declaration within.
extension Memory {
// Define a helper method for accessing a generated
// CLLocationCoordinate2D instance from the objects
// latitude and longitude values.
var locationCoordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(
latitude: latitude,
longitude: longitude
)
}
// Define a helper method that grabs all instances of a Memory
// sorted by their created date in ascending order.
static func allMemories() -> NSFetchRequest<Memory> {
let request: NSFetchRequest<Memory> = Memory.fetchRequest() as! NSFetchRequest<Memory>
let sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)
request.sortDescriptors = [sortDescriptor]
return request
}
}
任何帮助我的想法都将不胜感激。我认为,明天的问题会崭露头角!
编辑:这是MemoryRow
类:
import SwiftUI
struct MemoryRow: View {
var title: String = ""
var createdAt: String = ""
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(title)
.font(.headline)
Text(createdAt)
.font(.caption)
}
}
}
}
struct MemoryRow_Previews: PreviewProvider {
static var previews: some View {
MemoryRow(title: "Test Title", createdAt: "Test Date")
}
}
答案 0 :(得分:12)
在我的情况下,这是因为optional
数据类型是在我们向数据模型中添加属性时默认选择的,因此在NSManagedObjectClass
中看起来像这样
@NSManaged public var name: String?
当然,要解决此问题,可以在上一行中删除?
或在使用??
之类的属性时使用ClassName.name ?? "Unknown"
nil合并运算符
从给出的答案和评论中,我去检查了类中的属性名称是否有错字,然后我意识到了这个问题。现在必须处理SwiftUI
的这种行为,即它不会显示实际错误或在任何其他行上显示。?
希望这可以帮助像我这样的人。
答案 1 :(得分:2)
在闭包参数中设置NSManagedObject类型。
ForEach(books, id: \.self) { book in
//
}
到
ForEach(books, id: \.self) { (book: Book) in
//
}
答案 2 :(得分:2)
我有类似的问题,
var D: [ACoreDataEntity]
然后
filtered = D.filter{$0.name == 'john'}
名称正确是ACoreDataEntity
但是它不会解析或编译。
filtered = L.filter{($0).name == 'john'}
去吧。
答案 3 :(得分:1)
关于什么为我解决了这个问题,我实际上有点困惑。这是我之前做过的一些事情,“行之有效” 。
我不知道是哪个原因引起的,我只是重新打开了Xcode,以前失败的构建现在又在意外地构建。
因此,为了快速思考如何解决它,并使用Git diff作为某种参考形式,这是我按照以下顺序重新跟踪自己的步骤:
检查了SceneDelegate
上下文所面向的contentView
在View
中的视图附件。这对我来说是错误的NSManagedObjectContext
,它附加在View
而不是MemoryDetail()
上。
删除了违规行:
MemoryList()
并仅使用填充符MemoryRow(title: memoryItem.title!, createdAt: memoryItem.description)
替换它,即可成功保存并构建项目。
Text("test")
声明:sortDescriptor
到
let sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)
request.sortDescriptors = [sortDescriptor]
重新启动Xcode(尽管这样做多次,无论如何都无济于事)。
暂存而不是提交我跟踪的代码更改。
删除填充符request.sortDescriptors = [
NSSortDescriptor(key: "createdAt", ascending: true)
]
并手动键入该行:
Text("test")
其中的代码提示仍然不起作用,但是该行现在可以正常运行,因此您必须手动进行操作。不,展开力MemoryRow(title: memoryItem.title!, createdAt: memoryItem.description)
并不是错误的原因。
使用Git差异并粘贴我的原始代码后,我想我知道错误是什么
!
这没有帮助,因为编译器给出的错误与实际问题没有直接关系。错误应该是MemoryRow(title: memoryItem.title!, createdAt: memoryItem.createdAt)
// ^^^^^^^^^
// This is wrong ----------------------------------------//////////
未返回memoryItem.createdAt
期望的正确类型。
MemoryRow
我认为问题有时出在Xcode上,有些偶然危险。
此后,我对MemoryRow(title: memoryItem.title!, createdAt: "")
// Compiles fine
// And now the corrected version:
MemoryRow(title: memoryItem.title!, createdAt: "\(memoryItem.createdAt!)")
进行了修改,现在接受MemoryRow
类型,而不是Date?
,以更好地描述对象正在接受什么。以及解包,格式化和显示该类中的变量。
答案 4 :(得分:0)
尝试此构造以获取请求
@FetchRequest(
entity: Memory.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Memory.createdAt, ascending: true)
]
) var allMemories: FetchedResults<Memory>
答案 5 :(得分:0)
我认为处理此问题的正确方法是这样做
更改
MemoryRow(title: memoryItem.title, createdAt: memoryItem.createdAt)
到
MemoryRow(title: (memoryItem.title ?? ""), createdAt: (memoryItem.createdAt ?? ""))
答案 6 :(得分:0)
您必须指定要迭代的数组元素的类型(memoryItem:内存),例如:`。
中的.ForEach(self.allMemories){(memoryItem:Memory)在此处指定内存类型:
`
ForEach(self.allMemories) { (memoryItem: Memory) in
MemoryRow(title: memoryItem.title, createdAt: memoryItem.createdAt)
}
`
这是因为它可以是任何类型的NSManagedObject,但是为了使Swift确切地知道它是什么类型的托管对象,我们需要明确。结帐:https://www.hackingwithswift.com/books/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui
答案 7 :(得分:0)
我遇到了类似的错误。
就我而言,我有一个 CoreData 实体“Category”,它与“Contact”实体具有一对多关系。联系人具有 firstName
和 lastname
可选字符串属性。
我的确切错误是:
Value of type 'NSObject' has no member 'lastName'
在我的 SwiftUI 文本视图中尝试访问 contact.lastName 时。
解决方案似乎比我一开始假设的要简单,因为当这一切都不必要时,我对 set vs Array 进行了过多的读取:
(注意:此代码位于 if category.contacts?.count != 0 { }
内,因为我只想在有要显示的内容时显示列表。)
if category.contacts?.count != 0 {
List {
Section (header: Text("Contacts")) {
ForEach(contacts) { contact in
HStack (spacing: 4) {
Image(systemName: "person.crop.circle.fill")
Text("\(contact.firstName ?? "")")
Text("\(contact.lastName ?? "")")
Spacer()
}
}
}
}
.listStyle(InsetGroupedListStyle())
}
这个结构的开头像这样初始化contacts
:
struct CategoryForm: View {
@Environment(\.managedObjectContext) private var moc
@ObservedObject var category: Category
@State private var isEditing = false
@State private var errorAlertIsPresented = false
@State private var errorAlertTitle = ""
@FetchRequest var contacts: FetchedResults<Contact>
init(category: Category) {
self.category = category
var predicate: NSPredicate?
predicate = NSPredicate(format: "category = %@", category)
self._contacts = FetchRequest<Contact>(
sortDescriptors: [NSSortDescriptor( keyPath: \Contact.lastName, ascending: true),
NSSortDescriptor( keyPath: \Contact.firstName, ascending: true)],
predicate: predicate
)
}
var body: some View {
///etc...
对我来说,这个错误来自于将 NSSet 更改为数组的太多尝试。但 FetchRequest 是另一回事。所以,对我来说更简单更好。
///This line of code generated the error!
///The Text("\(contact.firstName ?? "")") was not actually the problem
///although that line is where Xcode showed the error
ForEach(Array(category.contacts! as Set), id: \.self) { contact in
...
答案 8 :(得分:0)