核心数据内存崩溃

问题描述:

我在我的项目中第一次使用核心数据,我觉得在我的方法中存在一个严重的问题。我所做的是我从服务器获取数据(数据也包括png)。将其保存在本地的核心数据中。然后在应用程序启动时,我将整个数据加载到一个数组中。然后这个数组用在我需要的地方。我认为我正在采取一种非常糟糕的做法。任何人都可以指导我什么应该是一个更好的方法?我应该只在需要数据时才查询核心数据,而不是在开始时将所有内容加载到内存中?核心数据内存崩溃

当数据被填充到数组中时,我可以看到Xcode中的内存增加,并且在某个值之后,它崩溃了。

这是我保存数据代码:

func saveDataLocally() { 

    let moContext = ((UIApplication.shared.delegate) as! AppDelegate).managedObjectContext 
    let entity = NSEntityDescription.entity(forEntityName: "FoodPlace", in: moContext) 

    for foodPlaceData in self.downloadedData_ { 
     let foodPlace = NSManagedObject(entity: entity!, insertInto: moContext) as! FoodPlace 
     foodPlace.objectId = foodPlaceData.objectId_ 
     foodPlace.name = foodPlaceData.name_ 
     foodPlace.address = foodPlaceData.address_ 
     foodPlace.keywords = foodPlaceData.keywords_ 
     foodPlace.baseFavourites = Int64(foodPlaceData.baseFavourites_) 
     foodPlace.startingTime = foodPlaceData.startingTime_ 
     foodPlace.endingTime = foodPlaceData.endingTime_ 
     foodPlace.category = foodPlaceData.category_ 
     foodPlace.basePrice = foodPlaceData.basePrice_ 
     foodPlace.dealTitle = foodPlaceData.dealTitle_ 
     foodPlace.versionNumber = Int64(foodPlaceData.versionNumber_) 
     foodPlace.menuItems = NSKeyedArchiver.archivedData(withRootObject: foodPlaceData.menuItems_) 
     foodPlace.location = NSKeyedArchiver.archivedData(withRootObject: foodPlaceData.location_) 
     foodPlace.deals = NSKeyedArchiver.archivedData(withRootObject: foodPlaceData.deals_) 
     foodPlace.foodPlacePhotos = NSKeyedArchiver.archivedData(withRootObject: foodPlaceData.foodPlacePhotos_) 

     moContext.insert(foodPlace) 
    } 

    do { 
     try moContext.save() 
    } 
    catch let error { 
     print("error saving = \(error.localizedDescription)") 
    } 
} 

其中menuItemsDictionary包含文本和PNG图像。另外,dealsfoodPlacePhotos只包含png图像。

这里是抓取代码:

func loadDataLocally() { 
    let moContext = ((UIApplication.shared.delegate) as! AppDelegate).managedObjectContext 
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "FoodPlace") 

    do { 
     let results = try moContext.fetch(request) 
     let savedFoodPlaceData = results as! [FoodPlace] 

     downloadedData_ = [] 

     for foodPlace in savedFoodPlaceData { 
      let objectId = foodPlace.objectId 
      let name = foodPlace.name 
      let address = foodPlace.address 
      let keywords = foodPlace.keywords 
      let baseFavourites = foodPlace.baseFavourites 
      let startingTime = foodPlace.startingTime 
      let endingTime = foodPlace.endingTime 
      let category = foodPlace.category 
      let menuItems = NSKeyedUnarchiver.unarchiveObject(with: foodPlace.menuItems!) as? [Dictionary<String,AnyObject>] 
      let location = NSKeyedUnarchiver.unarchiveObject(with: foodPlace.location!) as? Dictionary<String,Double> 
      let deals = NSKeyedUnarchiver.unarchiveObject(with: foodPlace.deals!) as? [UIImage] 
      let basePrice = Float(foodPlace.basePrice) 
      let dealTitle = foodPlace.dealTitle 
      let versionNumber = foodPlace.versionNumber 
      let foodPlacePhotos = NSKeyedUnarchiver.unarchiveObject(with: foodPlace.foodPlacePhotos!) as? [UIImage] 

      let data = FoodPlaceData(objectId: objectId!, name: name!, address: address!, category: category!, keywords: keywords!, baseFavourites: Int(baseFavourites), startingTime: startingTime!, endingTime: endingTime!, menuItems: menuItems!, location: location!, deals: deals!,basePrice: basePrice,dealTitle: dealTitle!,versionNumber: Int(versionNumber),foodPlacePhotos: foodPlacePhotos!) 

      downloadedData_.insert(data, at: downloadedData_.count) 
     } 
    } 
    catch let error { 
     print("error fetching = \(error.localizedDescription)") 
    } 
} 

,这里是删除数据的代码:

func deleteAllLocalData() { 
    let moContext = ((UIApplication.shared.delegate) as! AppDelegate).managedObjectContext 

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "FoodPlace") 
    fetchRequest.returnsObjectsAsFaults = false 

    do { 
     let results = try moContext.fetch(fetchRequest) 

     for managedObject in results { 
      let managedObjectData : NSManagedObject = managedObject as! NSManagedObject 
      moContext.delete(managedObjectData) 
     } 

     try moContext.save() 

    } catch let error { 
     print("Delete all data in FoodPlace error : \(error) \((error as NSError).userInfo)") 
    } 
} 
+0

尝试使用核心数据多线程。请通过https://code.tutsplus.com/tutorials/core-data-and-swift-concurrency--cms-25118 –

+0

谢谢你的回复,但我不认为这是我的问题。我有内存问题,它会占用太多的内存并因为内存不足而崩溃。我可以看到内存增加,超出一定的限制,它崩溃。 – kashif789us

+0

什么是数据量?我正面临内存问题,那么它也是线程管理的一部分。顺便看看这些https://github.com/mmorey/MDMHPCoreData https://www.youtube.com/watch?v=O7C6euzQt-o –

难没有关于你的代码了很多更详细地规定。但有一些想法:

  • 而不是将PNG数据存储在CoreData本身中,可以考虑将其直接存储在文件系统中,并使用CoreData仅存储PNG的文件名。
  • 或者,如果您确实需要CoreData中的PNG,请考虑为PNG添加一个单独的实体,并添加一个从当前实体到新实体的一对一关系。

以上任何一种都会避免在加载阵列时将所有PNG数据加载到内存中。然后,您可以根据需要加载/卸载PNG(从文件系统或相关实体)。

此外,可以考虑使用:

这将有助于避免所有对象被加载到内存中。

+0

我已经添加了代码。 – kashif789us