Swift saving multiple images to the filesystem at once, High CPU

社会主义新天地 提交于 2019-12-13 03:55:18

问题


I have the following func, I need to clear out all picture columns in a DB and move to the file system. When I did this all in one go, there was too much memory and it would crash. I switched to a recursive function and do the writes and batches of 20.

There are about 6 tables which I need to do this for. There is 2 and half gigs of data in my Realm DB. This gets switched to 40mb after I call my 6 recursive functions, taking images out and compressing Realm.

I can see very high memory usage as my functions are called and phones with less RAM would not be able to handle it.

How can I free up memory and CPU in between each function?

public static func clearEqCatPics(){

        let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let eqcatPicDir = docsDir.appendingPathComponent(util_Constants.DIR_EQCAT_PICS)

        do {
            var realm : Realm? = try Realm()
            let predicate = NSPredicate(format: "icon != %@", "")
            let categories = realm!.objects(STD_EQ_category.self).filter(predicate).sorted( by: [SortDescriptor(keyPath: "displayorder", ascending: true), SortDescriptor(keyPath: "_id", ascending: true)] )

            if (categories.count > 0)
            {
                realm?.beginWrite()
                let upper = categories.count > 20 ? 20 : categories.count

                var actualCounter = upper
                for i in 0..<upper{
                    autoreleasepool{
                        if let proPicData = Data(base64Encoded: categories[actualCounter - 1].icon, options: .ignoreUnknownCharacters) {


                            let filename = eqcatPicDir.appendingPathComponent(categories[actualCounter - 1]._id.description+".jpg")

                            (proPicData as NSData).writeToURL2(named: filename, completion: { (result, url) -> Void in

                            })

                            categories[actualCounter - 1].icon = ""

                        }
                        else{
                            categories[actualCounter - 1].icon = ""
                        }
                    }

                    actualCounter = actualCounter - 1

                }

                try realm?.commitWrite()
                let eqcatNew = realm!.objects(STD_EQ_category.self).filter(predicate)
                print("$$$$$$$$$$$$$$$$$$$$ 2. eqcatNew COUNT : \(eqcatNew.count) $$$$$$$$$$$$$$$$$$$$")
                realm = nil
                if eqcatNew.count > 0 {
                    clearEqCatPics()
                }
            }
            realm = nil
        }
        catch let error as NSError {
            print("error realm \(error.localizedDescription)")

        }

    }

where writeToURL2 IS:

I needed to get rid of the weak self in my extension because I was getting past the guard let for multiple items and loads were being skipped

extension NSData {

    func writeToURL2(named:URL, completion: @escaping (_ result: Bool, _ url:NSURL?) -> Void)  {


        let tmpURL = named as NSURL

        //[weak self]
        DispatchQueue.global(qos: .background).async {  () -> Void in

            //guard let strongSelf = self else { print("self was weak"); completion (false, tmpURL); return }

            self.write(to: tmpURL as URL, atomically: true)
            var error:NSError?
            if tmpURL.checkResourceIsReachableAndReturnError(&error) {
                print("We have it")
                completion(true, tmpURL)
            } else {
                print("We Don't have it\(error?.localizedDescription)")
                completion (false, tmpURL)
            }

        }

    }
}

EDIT:

I changed my writeToURL in my for loop to the following:

do {
     try proPicData.write(to: filename, options: [.atomic])                               
}
catch let err as NSError{
     print("err : \(err.localizedDescription)")
}

It helped with memory, But sometimes I get Thread1: EXC_BAD_ACCESS pointing to the line try proPicData.write...

Still have very high CPU usage. Is there anyway to clear out CPU usage in between each function call?


回答1:


You are fetching all of the objects in your Realm at the same time, that is what is using up so much memory

let categories = realm!.objects(STD_EQ_category.self).filter(predicate).sorted( by: [SortDescriptor(keyPath: "displayorder", ascending: true), SortDescriptor(keyPath: "_id", ascending: true)] )

The writing to files is not what is using up memory, although that might have something to do with the CPU usage.

I would recommend putting a limit on the categories fetch so that you don't load all categories and their images into memory. Otherwise, try to come up with a fetch predicate that would otherwise limit the data in a sensible way.



来源:https://stackoverflow.com/questions/55932996/swift-saving-multiple-images-to-the-filesystem-at-once-high-cpu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!