2016-10-03 140 views
0

我在我的項目中第一次使用核心數據,我覺得在我的方法中存在一個嚴重的問題。我所做的是我從服務器獲取數據(數據也包括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 –

回答

1

難沒有關於你的代碼了很多更詳細地規定。但有一些想法:

  • 而不是將PNG數據存儲在CoreData本身中,可以考慮將其直接存儲在文件系統中,並使用CoreData僅存儲PNG的文件名。
  • 或者,如果您確實需要CoreData中的PNG,請考慮爲PNG添加一個單獨的實體,並添加一個從當前實體到新實體的一對一關係。

以上任何一種都會避免在加載陣列時將所有PNG數據加載到內存中。然後,您可以根據需要加載/卸載PNG(從文件系統或相關實體)。

此外,可以考慮使用:

這將有助於避免所有對象被加載到內存中。

+0

我已經添加了代碼。 – kashif789us