核心数据内存崩溃

时间:2016-10-03 14:51:33

标签: ios swift core-data

我在项目中第一次使用Core Data,我觉得我的方法存在严重问题。我正在做的是我从服务器获取数据(数据也包括png)。将其保存在本地核心数据中。然后在app启动时,我将整个数据加载到一个数组中。然后在我需要的地方使用这个数组。我想我的方法非常糟糕。谁能指导我什么应该是更好的方法?我应该只在需要数据时查询核心数据而不是在开始时将所有内容加载到内存中吗?

当数据被填充到数组时,我可以看到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)")
    }
}

1 个答案:

答案 0 :(得分:1)

如果没有关于代码的更多详细信息,很难成为规范性的。但是有些想法:

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

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

此外,请考虑使用:

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