Tür bir NSFetchRequest örneğine nasıl uygulanır?


102

Swift 2'de aşağıdaki kod çalışıyordu:

let request = NSFetchRequest(entityName: String)

ama Swift 3'te hata veriyor:

Genel parametre "ResultType" çıkarılamadı

çünkü NSFetchRequestartık genel bir tür. Belgelerinde şunu yazdılar:

let request: NSFetchRequest<Animal> = Animal.fetchRequest

yani sonuç sınıfım örneğin, Levelnasıl doğru bir şekilde talep etmeliyim?

Çünkü bu çalışmıyor:

let request: NSFetchRequest<Level> = Level.fetchRequest

1
kodu bulduğum yeni özelliklere bağlantı: developer.apple.com/library/prerelease/content/releasenotes/…
Deniss

1
Bu bir yöntem, bu yüzden öyle olmalılet request: NSFetchRequest<Level> = Level.fetchRequest()
Sulthan

5
Ya da sadecelet request = Level.fetchRequest()
Martin R.

2
@MartinR Karmaşık olduğu için derlemeyi geçemez.
Sulthan

6
@MartinR yığın taşması üyeleri sizi çok seviyor gibi görünüyor. Size körü körüne oy verecekler. : P
BangOperator

Yanıtlar:


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

veya

let request: NSFetchRequest<Level> = Level.fetchRequest()

istediğiniz sürüme bağlı olarak.

Genel türü belirtmeniz gerekir çünkü aksi takdirde yöntem çağrısı belirsizdir.

İlk sürüm için tanımlanır NSManagedObject, ikinci sürüm bir uzantı kullanılarak her nesne için otomatik olarak oluşturulur, örneğin:

extension Level {
    @nonobjc class func fetchRequest() -> NSFetchRequest<Level> {
        return NSFetchRequest<Level>(entityName: "Level");
    }

    @NSManaged var timeStamp: NSDate?
}

Bütün mesele, String sabitlerinin kullanımını kaldırmaktır.


1
Yani her varlık için uzantı kodu eklemem gerekir mi? Yoksa bu otomatik olarak mı olur? Öyleyse, bir "Köpek" varlığım ve "Kedi" varlığım varsa, "uzatma Köpeği {@nonobjc ...}" ve "uzantı Kedi {@nonobjc ...}" gerekir mi?
Dave G

@DaveG Bu uzantı sizin için otomatik olarak oluşturulur.
Sulthan

1
Tamam, ty, ama biraz kafam karıştı çünkü 'letchRequest = NSFetchRequest <myEntityName> (entityName: "myEntityName")' denedim ve "Bildirilmemiş tür kullanımı" myEntityName "hatası aldım
Dave G

4
Not:
fetchRequest

@Sulthan Merhaba, Kodunuzu denediğimde aşağıdaki hata oluşuyor. Type 'Project Name' does not conform to protocol 'NSFetchRequestResult'
Svetoslav Atanasov

56

Sanırım şunu yaparak çalıştırdım:

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

en azından DataBase'den veri kaydeder ve yükler.

Ama uygun bir çözüm değil gibi geliyor ama şimdilik işe yarıyor.


Varlık adını parametre olarak alan ve NSManagedObjects dizisini geri veren tek bir yönteme sahip olduğum için bu çözümü daha çok seviyorum.
n_b

Bunu da beğendim çünkü özel bir sınıf oluşturmayı gerektirmiyordu. Sadece varlık adı kullanılabilir!
Liam Bolling

Yetersiz cevap. Teşekkürler!
David Chelidze

33

3.0'da çalıştığını bulduğum en basit yapı şu şekilde:

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

veri varlığı Türü Ülke'dir.

Ancak bir Temel Veri BatchDeleteRequest oluşturmaya çalışırken, bu tanımın işe yaramadığını ve şu formla gitmeniz gerekecek gibi görünüyor:

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

ManagedObject ve FetchRequestResult formatlarının eşdeğer olduğu varsayılsa bile.


1
Bu cevapta bahsedilen ilk yapı, Swift3 / iOS 10 / Xcode 8'de getirilen sonuç denetleyicimle bunu şu anda derlemenin tek yoludur.
David L

Bu, çeşitli formları denedikten sonra benim deneyimimdi. CoreData sunumundaki diğer formları kapsadılar mı? Yarın kontrol etmeyi planla ...
Ron Diel

İlk örnek, if #available(iOS 10.0) { ... }koşullu kullanmak zorunda kalmadan bulduğum en basit yol
djv

12

Sorunuzu yanıtlayabilecek bazı genel CoreData yöntemleri şunlardır:

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 için aşağıdaki gibi bir NSManagedObject kurulumu olduğunu varsayarsak:

class Contact: NSManagedObject
{
    @NSManaged var contactNo: Int
    @NSManaged var contactName: String
}

Bu yöntemler şu şekilde kullanılabilir:

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()

Temiz ve zarif. Keşke buna 100 oy verebilseydim! Tek bir rötuş, ne düşündüğünüzü merak ederek, iş parçacığı güvenliği için her yöntemi bağlam? .Perform ({}) ile sardım. Bu, Apple tarafından tavsiye edilmektedir.
Tinkerbell

Çok OO değil. Bunları NSManagedObjectContect'e bir uzantı olarak yazamazsanız, bu iyi bir çözüm olacaktır.
muz the axe

1
Sadece fark ettim - onları aldığınız tüm kayıtları saymak ve ardından dizi girişlerinin sayısını saymak - bu gerçekten verimsizdir. Context.count (istek)
muz the axe

Bunlar güzel eklemelerdir ve daha fazla oy almaları gerekir, ancak büyük olasılıkla ana sorudan uzaklaştığı için (yararlı olmasına rağmen) değil. Silme işleviyle değiştirmeyi zorlaştırdığım bir şey, NSManagedObjectIDbunun yerine ile silmektir . Yani önce context.delete(record)eklemek let record = context.object(with: record.objectID)ve silmek için bu rekor nesnesini kullanın.
PostCodeism

6

Bu, Swift 3.0'a geçmenin en basit yoludur. <Country>

(test edildi ve çalıştı)

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

0

Ben de "ResultType" vardı hatalar çıkarılamadı. Her bir varlığın Codegen'ini "Sınıf Tanımı" olarak ayarlayan veri modelini yeniden oluşturduğumda temizlediler. Burada adım adım talimatlarla kısa bir yazı yazdım:

Swift 3 ile Xcode 8'de revize edilmiş NSPersistentContainer hakkında net bir öğretici arıyorsunuz

"Yeniden oluşturulmuş" derken, yeni girişler ve özniteliklerle yeni bir model dosyası oluşturduğumu kastediyorum. Biraz sıkıcı ama işe yaradı!


0

Şimdiye kadar benim için en iyi sonuç veren şey şuydu:

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

0

Ben de aynı sorunu yaşadım ve aşağıdaki adımlarla çözdüm:

  • Xcdatamodeld dosyanızı seçin ve Veri Modeli Denetçisine gidin
  • İlk Varlığınızı seçin ve Bölüm sınıfına gidin
  • Codegen "Sınıf Tanımı" nın seçildiğinden emin olun.
  • Oluşturulan tüm Varlık dosyalarınızı kaldırın. Artık onlara ihtiyacınız yok.

Bunu yaptıktan sonra fetchRequest'in tüm oluşumlarını kaldırmak / yeniden yazmak zorunda kaldım çünkü XCode, kodla oluşturulmuş sürümle bir şekilde karışıyor gibi görünüyor.

HTH


0

Swift 3.0 Bu çalışmalıdır.

let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.