核心数据NSInvalidArgument异常

时间:2019-09-30 16:26:50

标签: ios swift core-data

我正在关注本教程https://medium.com/@jamesrochabrun/parsing-json-response-and-save-it-in-coredata-step-by-step-fb58fc6ce16f

但是在达到获取阶段之前,我按照该教程的建议运行了该应用,以获取存储数据的filePath

我的应用程序崩溃了,我得到了错误消息

'NSInvalidArgumentException', reason: '+entityForName: nil is not a

legal NSManagedObjectContext parameter searching for entity name 
'NewsObject''

我环顾四周,发现了这个iOS: Swift: Core Data: Error: +entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name

Core Data Reading Data

他们都建议确保manageObjectContext不为零。但是我不怎么实现/确保它不是nil

我是CoreData的一个完整的初学者,刚刚从该教程开始

这是我的代码


 private func createNewsEntityFrom(dictionary: [String: Any]) -> NSManagedObject? {
        let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
        if let newsEntity = NSEntityDescription.insertNewObject(forEntityName: "NewsObject", into: context) as? NewsObject {
            newsEntity.newsAuthor = dictionary["author"] as? String ?? "default"
            newsEntity.newsTitle = dictionary["title"] as? String ?? "default"
            let images = dictionary["image"] as? [String: AnyObject]
            newsEntity.newsImageURL = images?["link"] as? String ?? "default"
            return newsEntity
        }
        return nil
    }

    private func saveInCoreDataWith(array: [[String: Any]]) {
        for dict in array {
            _ = self.createNewsEntityFrom(dictionary: dict)
        }
        do {
            try CoreDataStack.sharedInstance.persistentContainer.viewContext.save()
        } catch let error {
            print(error)
        }
    }
  let url = "someURL"
            Alamofire.request(url, method: .get , headers: headers).responseJSON { response in
                switch response.result {
                case .success:
                    let json = response.result.value as! [String:Any]
                    let data = json["data"] as! [[String : Any]]
                    self.saveInCoreDataWith(array: data)
                    self.nextToken = json["nextPageToken"] as? String ?? "empty"
                    print("Token = "+self.nextToken!)
                    for dic in data{
                        self.news.append(News(dictionary: dic))
                        print(self.news.count)

                    }
                    DispatchQueue.main.async {
                        loadingIndicator.stopAnimating()
                        self.tableView.reloadData()
                    }


                case .failure: break
                }

我的CoreDataStack类



import UIKit
import Foundation
import CoreData

class CoreDataStack: NSObject {

    static let sharedInstance = CoreDataStack()
    private override init() {}

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
         */
        let container = NSPersistentContainer(name: "TapIn")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

}

extension CoreDataStack {

    func applicationDocumentsDirectory() {
        // The directory the application uses to store the Core Data store file. This code uses a directory named "yo.BlogReaderApp" in the application's documents directory.
        if let url = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).last {
            print(url.absoluteString)
        }
    }
}

编辑:这是我用来保存接收到的数据并对其执行各种功能的结构新闻

//Model to hold our news
   struct News {
    var image : String
    var title : String
    var publisherIcon : String
    var publisher : String
    var author : String
    var time : Int
    var id : String
    var bookmarked : Bool
    var liked : Bool

    init(dictionary : [String:Any])
    {
        let image = dictionary["image"] as? [String:Any]
        self.image = image!["link"] as! String
        self.title = dictionary["title"] as? String ?? ""
        self.publisherIcon = dictionary["shortenedLogo"] as? String ?? ""
        self.publisher =  dictionary["publisher"] as? String ?? ""
        self.author = dictionary["author"] as? String ?? ""
        self.time = dictionary["timeToRead"] as? Int ?? 0
        self.id = dictionary["_id"] as? String ?? ""
        self.bookmarked = dictionary["bookmarked"] as? Bool ?? false
        self.liked = dictionary["liked"] as? Bool ?? false
    }

}

在主VC var news = [News]()

1 个答案:

答案 0 :(得分:1)

在单例中添加此惰性实例化属性以获取非可选上下文

lazy var managedObjectContext : NSManagedObjectContext = {
    return self.persistentContainer.viewContext
}()

并使用现代API插入对象

 private func createNewsEntityFrom(dictionary: [String: Any]) -> NewsObject {
    let context = CoreDataStack.sharedInstance.managedObjectContext
    let newsEntity = NewsObject(context: context)
    newsEntity.newsAuthor = dictionary["author"] as? String ?? "default"
    newsEntity.newsTitle = dictionary["title"] as? String ?? "default"
    let images = dictionary["image"] as? [String: Any]
    newsEntity.newsImageURL = images?["link"] as? String ?? "default"
    return newsEntity
 }

并且根据命名准则,强烈建议命名实体和属性,例如减少冗余的

 private func createNews(from dictionary: [String: Any]) -> News {
    let context = CoreDataStack.sharedInstance.managedObjectContext
    let news = News(context: context)
    news.author = dictionary["author"] as? String ?? "default"
    news.title = dictionary["title"] as? String ?? "default"
    let images = dictionary["image"] as? [String: Any]
    news.imageURL = images?["link"] as? String ?? "default"
    return news
 }

通过applicationDocumentsDirectory函数错误的方式。一定是

func applicationDocumentsDirectory() -> URL {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "yo.BlogReaderApp" in the application's documents directory.
    return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
}

编辑:

要返回插入的数组,您必须将saveInCoreDataWith更改为

private func saveInCoreDataWith(array: [[String: Any]]) -> [NewsObject] {
    var newsArray = [NewsObject]()
    for dict in array {
        newsArray.append(self.createNewsEntityFrom(dictionary: dict))
    }
    do {
        try CoreDataStack.sharedInstance.managedObjectContext.save()
        return newsArray
    } catch let error {
        print(error)
    }
    return []
}

并在Alamofire封口中替换

self.saveInCoreDataWith(array: data)
self.nextToken = json["nextPageToken"] as? String ?? "empty"
print("Token = "+self.nextToken!)
for dic in data{
   self.news.append(News(dictionary: dic))
   print(self.news.count)                   
}

使用

self.news = self.saveInCoreDataWith(array: data)
self.nextToken = json["nextPageToken"] as? String ?? "empty"
print("Token = "+self.nextToken!)
print(self.news.count)