Как применить тип к экземпляру NSFetchRequest?
В 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
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?
}
Все дело в том, чтобы удалить использование строковых констант.
Ответ 2
Я думаю, что у меня это получилось:
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")
по крайней мере, он сохраняет и загружает данные из базы данных.
Но похоже, что это не правильное решение, но оно работает пока.
Ответ 3
Простейшая структура, которую я нашел, которая работает в версии 3.0, выглядит следующим образом:
let request = NSFetchRequest<Country>(entityName: "Country")
где объект данных Тип - страна.
Тем не менее, при попытке создать базовый файл BatchDeleteRequest я обнаружил, что это определение не работает, и вам кажется, что вам нужно перейти к форме:
let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()
хотя форматы ManagedObject и FetchRequestResult должны быть эквивалентными.
Ответ 4
Это самый простой способ перехода на Swift 3.0, просто добавьте <Country>
(проверено и обработано)
let request = NSFetchRequest<Country>(entityName: "Country")
Ответ 5
Вот некоторые общие методы 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()
Ответ 6
У меня также был "ResultType" не может быть выведенных ошибок. Они очистились, как только я перестроил модель данных, устанавливая для каждого объекта Codegen значение "Определение класса". Я сделал краткую запись с пошаговыми инструкциями здесь:
Ищет четкое руководство по пересмотренному NSPsistentContainer в Xcode 8 с Swift 3
Под "rebuilt" я имею в виду, что я создал новый файл модели с новыми записями и атрибутами. Немного утомительно, но это сработало!
Ответ 7
То, что работало лучше всего для меня до сих пор, было:
let request = Level.fetchRequest() as! NSFetchRequest<Level>
Ответ 8
У меня была такая же проблема, и я решил ее с помощью следующих шагов:
- Выберите файл xcdatamodeld и перейдите к Data Model Inspector
- Выберите свой первый объект и перейдите в раздел Класс
- Убедитесь, что выбрано Codegen "Определение класса".
- Удалите все созданные вами файлы Entity. Они вам больше не нужны.
После этого мне пришлось удалить/переписать все вхождения fetchRequest, поскольку XCode, похоже, каким-то образом смешивается с кодированной версией.
НТН