如何将类型应用于 NSFetchRequest 实例?
Posted
技术标签:
【中文标题】如何将类型应用于 NSFetchRequest 实例?【英文标题】:How to apply the type to a NSFetchRequest instance? 【发布时间】:2016-06-14 11:39:59 【问题描述】:在 Swift 2 中,以下代码可以正常工作:
let request = NSFetchRequest(entityName: String)
但在 Swift 3 中会报错:
无法推断通用参数“ResultType”
因为NSFetchRequest
现在是泛型类型。他们在他们的文件中写道:
let request: NSFetchRequest<Animal> = Animal.fetchRequest
所以如果我的结果类是例如Level
我应该如何正确请求?
因为这不起作用:
let request: NSFetchRequest<Level> = Level.fetchRequest
【问题讨论】:
链接到新功能,我在这里找到了代码:developer.apple.com/library/prerelease/content/releasenotes/… 是一个方法,所以应该是let request: NSFetchRequest<Level> = Level.fetchRequest()
或者只是let request = Level.fetchRequest()
@MartinR 这不会通过编译,因为它是模棱两可的。
@MartinR 似乎堆栈溢出成员非常喜欢你。他们会盲目地支持你。 :P
【参考方案1】:
let request: NSFetchRequest<NSFetchRequestResult> = Level.fetchRequest()
或
let request: NSFetchRequest<Level> = Level.fetchRequest()
取决于你想要的版本。
您必须指定泛型类型,否则方法调用不明确。
第一个版本是为NSManagedObject
定义的,第二个版本是为每个使用扩展名的对象自动生成的,例如:
extension Level
@nonobjc class func fetchRequest() -> NSFetchRequest<Level>
return NSFetchRequest<Level>(entityName: "Level");
@NSManaged var timeStamp: NSDate?
重点是删除字符串常量的使用。
【讨论】:
那么对于每个实体,我需要添加扩展代码吗?或者那是自动发生的?所以如果我有一个“狗”实体和“猫”实体,我需要“扩展狗@nonobjc...”和“扩展猫@nonobjc...”吗? @DaveG 该扩展是自动为您生成的。 好吧,你,但我有点困惑,因为我尝试了 'let fetchRequest = NSFetchRequestType 'Project Name' does not conform to protocol 'NSFetchRequestResult'
【参考方案2】:
我想我这样做是为了让它工作:
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")
至少它从数据库中保存和加载数据。
但感觉这不是一个合适的解决方案,但它现在有效。
【讨论】:
我更喜欢这个解决方案,因为我以前有一个方法,它把实体名称作为参数,然后传回一个 NSManagedObjects 数组。 也喜欢这个,因为它不需要创建自定义类。只能使用实体名称!【参考方案3】:我发现在 3.0 中工作的最简单的结构如下:
let request = NSFetchRequest<Country>(entityName: "Country")
其中数据实体类型是国家。
但是,当尝试创建 Core Data BatchDeleteRequest 时,我发现此定义不起作用,您似乎需要使用表单:
let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()
即使 ManagedObject 和 FetchRequestResult 格式应该是等效的。
【讨论】:
这个答案中提到的第一个结构是我目前可以在 Swift3 / iOS 10 / Xcode 8 上使用我获取的结果控制器进行编译的唯一方法。 这是我尝试各种形式后的经验。他们是否涵盖了 CoreData 演示文稿中的任何其他形式?打算明天去看看…… 第一个例子是我发现的最简单的方法,无需使用if #available(iOS 10.0) ...
条件【参考方案4】:
这里有一些通用的 CoreData 方法可能会回答您的问题:
import Foundation
import Cocoa
func addRecord<T: NSManagedObject>(_ type : T.Type) -> T
let entityName = T.description()
let context = app.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
let record = T(entity: entity!, insertInto: context)
return record
func recordsInTable<T: NSManagedObject>(_ type : T.Type) -> Int
let recs = allRecords(T.self)
return recs.count
func allRecords<T: NSManagedObject>(_ type : T.Type, sort: NSSortDescriptor? = nil) -> [T]
let context = app.managedObjectContext
let request = T.fetchRequest()
do
let results = try context.fetch(request)
return results as! [T]
catch
print("Error with request: \(error)")
return []
func query<T: NSManagedObject>(_ type : T.Type, search: NSPredicate?, sort: NSSortDescriptor? = nil, multiSort: [NSSortDescriptor]? = nil) -> [T]
let context = app.managedObjectContext
let request = T.fetchRequest()
if let predicate = search
request.predicate = predicate
if let sortDescriptors = multiSort
request.sortDescriptors = sortDescriptors
else if let sortDescriptor = sort
request.sortDescriptors = [sortDescriptor]
do
let results = try context.fetch(request)
return results as! [T]
catch
print("Error with request: \(error)")
return []
func deleteRecord(_ object: NSManagedObject)
let context = app.managedObjectContext
context.delete(object)
func deleteRecords<T: NSManagedObject>(_ type : T.Type, search: NSPredicate? = nil)
let context = app.managedObjectContext
let results = query(T.self, search: search)
for record in results
context.delete(record)
func saveDatabase()
let context = app.managedObjectContext
do
try context.save()
catch
print("Error saving database: \(error)")
假设有这样一个联系人的 NSManagedObject 设置:
class Contact: NSManagedObject
@NSManaged var contactNo: Int
@NSManaged var contactName: String
这些方法可以通过以下方式使用:
let name = "John Appleseed"
let newContact = addRecord(Contact.self)
newContact.contactNo = 1
newContact.contactName = name
let contacts = query(Contact.self, search: NSPredicate(format: "contactName == %@", name))
for contact in contacts
print ("Contact name = \(contact.contactName), no = \(contact.contactNo)")
deleteRecords(Contact.self, search: NSPredicate(format: "contactName == %@", name))
recs = recordsInTable(Contact.self)
print ("Contacts table has \(recs) records")
saveDatabase()
【讨论】:
干净优雅。希望我能投票赞成 100!一个修饰,想知道你的想法,我用 context?.perform() 包装了每个方法以确保线程安全。这是 Apple 推荐的。 不是很OO。除非您能够将这些编写为 NSManagedObjectContect 的扩展,否则这将是一个不错的解决方案。 刚刚注意到 - 计算您正在检索它们的所有记录,然后计算数组条目的数量 - 这确实效率低下。您可能希望扩展 recordsInTable 函数以利用 context.count(request) 这些是很好的补充,应该有更多的投票,但可能不是因为它偏离了主要问题(尽管它很有用)。我建议很难使用删除功能进行更改,而是使用NSManagedObjectID
删除。所以在context.delete(record)
之前添加let record = context.object(with: record.objectID)
并使用该记录对象删除。【参考方案5】:
这是迁移到 Swift 3.0 最简单的方法,只需添加 <Country>
(经过测试和工作)
let request = NSFetchRequest<Country>(entityName: "Country")
【讨论】:
【参考方案6】:Swift 3.0 这应该可以工作。
let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
【讨论】:
【参考方案7】:我也有“ResultType”无法推断错误。一旦我重建将每个实体的 Codegen 设置为“类定义”的数据模型,它们就会清除。我在这里做了一个简短的文章,并附有分步说明:
Looking for a clear tutorial on the revised NSPersistentContainer in Xcode 8 with Swift 3
“重建”是指我创建了一个具有新条目和属性的新模型文件。有点乏味,但确实有效!
【讨论】:
【参考方案8】:到目前为止,最适合我的是:
let request = Level.fetchRequest() as! NSFetchRequest<Level>
【讨论】:
【参考方案9】:我遇到了同样的问题,我通过以下步骤解决了它:
选择您的 xcdatamodeld 文件并转到数据模型检查器 选择您的第一个实体并转到部分类 确保选中 Codegen“类定义”。 删除所有生成的实体文件。你不再需要它们了。在这样做之后,我不得不删除/重写所有出现的 fetchRequest,因为 XCode 似乎以某种方式与代码生成的版本混淆了。
HTH
【讨论】:
【参考方案10】:let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func loadItemsCategory()
let request: NSFetchRequest<Category> = Category.fetchRequest()
do
categoryArray = try context.fetch(request)
catch
print(error)
tableView.reloadData()
【讨论】:
以上是关于如何将类型应用于 NSFetchRequest 实例?的主要内容,如果未能解决你的问题,请参考以下文章
技术实操如何使用GoLang将JT808协议中的DWORD类型转为string?
NSFetchRequest 返回具有 <invalid> 类型元素的数组