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