如何将类型应用于NSFetchRequest实例?


102

在Swift 2中,以下代码正在运行:

let request = NSFetchRequest(entityName: String)

但是在Swift 3中它给出了错误:

无法推断通用参数“ ResultType”

因为NSFetchRequest现在是通用类型。他们在文件中写道:

let request: NSFetchRequest<Animal> = Animal.fetchRequest

因此,例如,如果我的结果类是Level我应该如何正确请求?

因为这不起作用:

let request: NSFetchRequest<Level> = Level.fetchRequest

1
链接到新的功能,在这里我找到了代码:developer.apple.com/library/prerelease/content/releasenotes/...
Deniss

1
这是一种方法,所以应该是let request: NSFetchRequest<Level> = Level.fetchRequest()
Sulthan

5
或者只是let request = Level.fetchRequest()
Martin R

2
@MartinR那不会通过编译,因为它含糊不清。
Sulthan

6
@MartinR似乎堆栈溢出成员非常喜欢您。他们会盲目支持你。:P
BangOperator 2016年

Answers:


129
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?
}

重点是删除String常量的用法。


1
因此,对于每个实体,我都需要添加扩展代码吗?还是自动发生?因此,如果我有“狗”实体和“猫”实体,是否需要“扩展名狗{@nonobjc ...}”和“扩展名猫{@nonobjc ...}”?
戴夫G'9

@DaveG该扩展名是自动为您生成的。
苏珊(Sulthan)2013年

1
好的,ty,但是我有点困惑,因为我尝试了'let fetchRequest = NSFetchRequest <myEntityName>(entityName:“ myEntityName”)),并且收到错误消息“ Use of unclared type” myEntityName“
Dave G

4
注意:方法fetchRequest()仅在iOS 10中可用
dzensik

@Sulthan嗨,当我尝试使用您的代码时,发生以下错误。Type 'Project Name' does not conform to protocol 'NSFetchRequestResult'
Svetoslav Atanasov

56

我想我可以通过以下方法来工作:

let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")

至少它可以从数据库中保存和加载数据。

但这似乎不是一个适当的解决方案,但目前可以使用。


我以前更喜欢这种解决方案,因为我曾经有一个方法以实体名称作为参数,然后只传递了一个NSManagedObjects数组。
n_b

也喜欢它是因为它不需要创建自定义类。只能使用实体名称!
利亚姆·波林

被低估的答案。谢谢!
David Chelidze

33

我发现在3.0中工作的最简单的结构如下:

let request = NSFetchRequest<Country>(entityName: "Country")

其中数据实体类型为国家。

但是,当尝试创建Core Data BatchDeleteRequest时,我发现此定义不起作用,似乎您需要使用以下形式:

let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()

即使ManagedObject和FetchRequestResult格式应该等效。


1
在这个答案中提到的第一个结构是我目前能得到这个与Swift3 / iOS的10/8的Xcode我取结果控制器编译的唯一途径
大卫大号

这是我尝试各种形式后的经验。它们在CoreData演示文稿中是否涵盖了其他任何形式?计划明天检查出来...
罗恩·迪尔

第一个示例是我发现的最简单方法,而无需使用if #available(iOS 10.0) { ... }有条件
djv

12

以下是一些通用的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)")
    }
}

假设有一个类似于Contact的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的扩展,否则那将是一个不错的解决方案。
muz theax

1
刚注意到-要对所有记录进行计数,然后对它们进行计数,然后对数组条目的数量进行计数-这确实效率很低。您可能想扩展recordsInTable函数以利用context.count(request)
将斧头砍成

这些是不错的补充,应该有更多票数,但是可能不是因为它与主要问题背道而驰(尽管它很有用)。我建议很难用delete功能更改的东西是改为使用delete NSManagedObjectID。因此,在context.delete(record)添加 let record = context.object(with: record.objectID)并使用该记录对象删除之前。
PostCodeism

6

这是迁移到Swift 3.0的最简单方法,只需添加 <Country>

(经过测试和工作)

let request = NSFetchRequest<Country>(entityName: "Country")


0

到目前为止,最适合我的是:

let request = Level.fetchRequest() as! NSFetchRequest<Level>

0

我遇到了同样的问题,并通过以下步骤解决了该问题:

  • 选择您的xcdatamodeld文件,然后转到数据模型检查器
  • 选择您的第一个实体并转到Section类
  • 确保选择了Codegen“类定义”。
  • 删除所有生成的实体文件。您不再需要它们。

这样做之后,我不得不删除/重写所有出现的fetchRequest,因为XCode似乎以某种方式与代码生成的版本混合在一起。

高温超导


0

Swift 3.0这应该工作。

let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.