【问题标题】:Loading saved context from AppDelegate to another ViewController将保存的上下文从 AppDelegate 加载到另一个 ViewController
【发布时间】:2017-09-03 13:39:48
【问题描述】:

我正在尝试使我的 Viewcontroller 中的数组等于我的核心数据保存的对象。我正在使用核心数据并创建了一个名为 Pokemon 的实体,它具有 3 个属性 name、id 和 >一代。在应用程序委托中,我使用以下函数从 API 获取 Pokemon。这就是我解析数据并保存上下文的方法:

 typealias DownloadCompleted = () -> ()
 var pokemonId: Int16 = 0

func fetchPokemon(url: String, completed: @escaping DownloadCompleted) {
    let context = coreData.persistentContainer.viewContext

    let url = URLRequest(url: URL(string: url)!)

    let task = URLSession.shared.dataTask(with: url) { (data, repsonse, error) in
        if error != nil {
            print(error!)
        }

        do {

            let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
            let jsonArray = jsonResult.value(forKey: "results") as! [[String: Any]]
            for pokemonData in jsonArray {
                self.pokemonId += 1

                if self.pokemonId > 721 {

                    self.coreData.saveContext()
                    return
                }

                guard let name = pokemonData["name"] as? String else {
                    return
                }

                let pokemon = Pokemon(context: context)
                pokemon.name = name
                pokemon.id = self.pokemonId
                print("Name: \(pokemon.name) Id:\(self.pokemonId)")

                if self.pokemonId <= 151 {
                    pokemon.generation = 1
                } else if self.pokemonId <= 251 {
                    pokemon.generation = 2
                }  else if self.pokemonId <= 386 {
                    pokemon.generation = 3
                } else if self.pokemonId <= 493 {
                    pokemon.generation = 4
                } else if self.pokemonId <= 649 {
                    pokemon.generation = 5
                } else if self.pokemonId <= 721 {
                    pokemon.generation = 6
                }

            }



            guard let nextURL = jsonResult.value(forKey: "next") as? String else {
                self.coreData.saveContext()
                return
            }

            DispatchQueue.main.async {
                self.fetchPokemon(url: nextURL, completed: { 
                    self.coreData.saveContext()
                })
                completed()
            }

        } catch let err {
            print(err.localizedDescription)
        }



    }
    task.resume()

}

这就是我在 appDelegate 中的称呼。真的不知道在 fetchPokemon 中间该做什么或如何在另一个视图控制器中调用它。所以我把它留空,不确定这是否与我遇到的问题有关。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    let context = self.coreData.persistentContainer.viewContext
    let pokemonListVC = self.window?.rootViewController as! PokemonListVC
    pokemonListVC.context = context
    fetchPokemon(url: pokemonAPI) {

    }
    return true
}

我正在使用应用商店中的这个 SQL-Light 只读应用。我检查了数据,所有 721 只宠物小精灵都在保存。现在,我不知道如何使视图控制器中的数组等于保存的所有 721 个 Pokemon。我将此代码添加到我的 viewController 中。

class PokemonListVC: UIViewController {

  weak var context: NSManagedObjectContext! {
      didSet {
        return pokemon = Pokemon(context: context)
      }
  }
  var pokemon: Pokemon? = nil
  lazy var pokemons = [Pokemon]()
  override func viewDidLoad() {
      super.viewDidLoad()
      loadData()
  }

  func loadData() {
    pokemons = pokemon!.loadPokemon(generation: 1, context: context)
  }
}

我创建了我的口袋妖怪实体的扩展,并添加了一个函数 loadPokemon,它按代过滤口袋妖怪。这是代码。

extension Pokemon {

func loadPokemon(generation: Int16 = 0, context: NSManagedObjectContext) -> [Pokemon] {
    let request: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()
        request.predicate = NSPredicate(format: "generation = %@", generation)
        request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        do {
            let pokemons = try context.fetch(request)
            print("My Pokemon count: \(pokemons.count)")
            return pokemons
        } catch let err {
            print(err.localizedDescription)
        }
    return []
}

}

当我在 ViewController 中调用 loadData 时,它会崩溃。数组计数为 0,英雄扩展中的数组计数也是 0。所以我不怎么让我的数组等于从 coreData 保存的口袋妖怪。

非常感谢提供的任何帮助。 :)

这是我的 deleteRecords 代码,它也在我的 appDelegate 中。这会在应用启动时删除所有记录。我在 fetchPokemons 之前的 didFinishLaunchingWithOption 函数的最开始调用了这个方法。

func deleteRecords() {
    let context = coreData.persistentContainer.viewContext
    let pokemonRequest: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()

    var deleteRequest: NSBatchDeleteRequest
    var deleteResults: NSPersistentStoreResult

    do {
        deleteRequest = NSBatchDeleteRequest(fetchRequest: pokemonRequest as! NSFetchRequest<NSFetchRequestResult>)
        deleteResults = try context.execute(deleteRequest)
    } catch let err {
        print(err.localizedDescription)
    }

}

【问题讨论】:

    标签: ios json swift core-data


    【解决方案1】:

    正如您所说,您确定所有 pockemon 记录都正确存储在您的 coredata 中,您可以通过提供 fetch 请求来简单地从您的 codedata 中获取记录。我已经为联系人存储创建了演示,我可以通过此获取请求获取所有联系人,您可以在要获取所有记录的 ViewController 中尝试此代码。

     let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSManagedObject> (entityName: "Pokemon")
    
        do {
            arrPockemon = try managedContext.fetch(fetchRequest)
    
        }catch let error as NSError {
            showAlert(string: error.localizedDescription)
        }
    

    首先尝试获取所有记录,如果获得所有记录,则继续过滤扩展名和所有记录。希望它会帮助你。你可以在这里学习https://code.tutsplus.com/tutorials/core-data-and-swift-core-data-stack--cms-25065

    在 userDefault 上保存标志。

     //check for first time when app is installed first time(first time flag is not present so)
        let userDefault = UserDefaults.standard.dictionaryRepresentation()
        if userDefault.keys.contains("isDataAvailable") {
            //key is availebe so check it
            if userDefault["isDataAvailable"] as! String == "1"{
                //no need to call server for data
            }else{
                //fetch data from server
                // once you get data from server make isDataAvailable flage as 1
                UserDefaults.standard.setValue("1", forKey: "isDataAvailable")
                UserDefaults.standard.synchronize()
            }
        }
        else{
            //flag is not avalable so call server for data
            // once you get data from server make isDataAvailable flage as 1
            UserDefaults.standard.setValue("1", forKey: "isDataAvailable")
            UserDefaults.standard.synchronize()
        }
    

    【讨论】:

    • 我在应用委托中没有核心数据堆栈。我将它从应用程序委托移到了我创建的单独文件中。
    • 好的,那么你可以试试这个,让 context = coreData.persistentContainer.viewContext 并尝试获取记录。
    • 好吧,当我注释掉我的 deleteRecords() 方法时它一开始可以工作,但是当我取消注释它时,数组是 0。
    • 请发布您在 deleteRecords() 中的内容以及您在哪里调用它。
    • 刚刚添加了deleteRecords功能
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    相关资源
    最近更新 更多