【问题标题】:How to save in background in a loop swift如何在循环中快速保存在后台
【发布时间】:2016-06-30 09:18:30
【问题描述】:

我将数据作为数组存储在 NSUserDefaults 中。我需要使用 Parse Server 获取这些数据并将其存储在数据库中。当我尝试遍历数组并使用 saveInBackgroundWithBlock 时,循环再次运行,在块完成之前设置新值。将此数据作为单个对象保存在数据库中的最佳方法是什么?

let other = PFObject(className: "Other")
if (NSUserDefaults.standardUserDefaults().objectForKey("otherTypes") != nil) && (NSUserDefaults.standardUserDefaults().objectForKey("otherCosts") != nil) {
        otherCosts = NSUserDefaults.standardUserDefaults().objectForKey("otherCosts") as! [Double]

        otherTypes = NSUserDefaults.standardUserDefaults().objectForKey("otherTypes") as! [String]

        for costs in otherCosts {

            other.setObject(PFUser.currentUser()!.objectId!, forKey: "userId")
            other.setObject(otherTypes[i], forKey: "otherName")
            let cost = String(costs)
            other.setObject(cost, forKey: "otherCost")
            i = i + 1
            other.saveInBackgroundWithBlock({ (success, error) -> Void in
                if error == nil {
                    print("Success")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherTypes")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherCosts")
                } else {
                    print("Fail")
                }
            })
        } 

【问题讨论】:

  • 查看 NSCondition 类,它允许一个线程等待其他线程的完成。使用它,您可以等待之前的 save() 完成,然后再开始循环。
  • 您想要 Parse 中的多个 Other 对象还是一个包含两个数组的对象?

标签: ios arrays swift parse-platform


【解决方案1】:

您需要在 for 循环中分配PFObject inside,否则您只是一遍又一遍地处理同一个对象。

if (NSUserDefaults.standardUserDefaults().objectForKey("otherTypes") != nil) && (NSUserDefaults.standardUserDefaults().objectForKey("otherCosts") != nil) {
        otherCosts = NSUserDefaults.standardUserDefaults().objectForKey("otherCosts") as! [Double]

        otherTypes = NSUserDefaults.standardUserDefaults().objectForKey("otherTypes") as! [String]

        for costs in otherCosts {
            let other = PFObject(className: "Other")
            other.setObject(PFUser.currentUser()!, forKey: "userId")
            other.setObject(otherTypes[i], forKey: "otherName")
            let cost = String(costs)
            other.setObject(cost, forKey: "otherCost")
            i = i + 1
            other.saveInBackgroundWithBlock({ (success, error) -> Void in
                if error == nil {
                    print("Success")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherTypes")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherCosts")
                } else {
                    print("Fail")
                }
            })
        }

作为

【讨论】:

    【解决方案2】:

    您可以在后台线程上运行所有这些并使用信号量进行阻塞:

    let semaphore = dispatch_semaphore_create(0)
    for costs in otherCosts {
        //...
        other.saveInBackgroundWithBlock({ (success, error) -> Void in
            // ...
            dispatch_semaphore_signal(semaphore)
        })
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
    }
    

    请注意,由于这是一个长时间运行的操作,您绝对不希望在前台线程中执行此保存操作。

    另一种可能性是将整个事情转换为工作队列排列,如下所示:

    func tryToSend() {
        let defaults = NSUserDefaults.standardUserDefaults()
        if let otherTypes = defaults.objectForKey("otherTypes") as? [String],
            let otherCosts = defaults.objectForKey("otherCosts") as? [Double] {
                if otherTypes.count > 0 {
                    let other = PFObject(className: "Other")
                    other.setObject(PFUser.currentUser()!.objectId!, forKey: "userId")
                    other.setObject(otherTypes[0], forKey:"otherName")
                    other.setObject("\(otherCosts[0])", forKey:"otherCost")
                    other.saveInBackgroundWithBlock({ (success, error) -> Void in
                        if error == nil {
                            print("Success")
                            otherTypes = otherTypes[1..<otherTypes.count]
                            otherCosts = otherCosts[1..<otherCosts.count]
                            defaults.setObject(otherTypes, forKey: "otherTypes")
                            defaults.setObject(otherCosts, forKey: "otherCosts")
                            tryToSend()
                        } else {
                            print("Fail")
                        }
                    })
                }
        }
    }
    

    这样做的好处是您不必担心分离另一个线程,并且您可以动态地向 otherTypes 和 otherCosts 添加更多条目(通过适当的同步以确保 NSUserDefaults 在读取时不会被修改)

    在这种情况下,最后一个想法是使用PFObject.saveAllInBackground 方法在一个网络操作中完成整个操作,如下所示:

    let defaults = NSUserDefaults.standardUserDefaults()
    if let otherTypes = defaults.objectForKey("otherTypes") as? [String],
        let otherCosts = defaults.objectForKey("otherCosts") as? [Double] {
            let others = zip(otherTypes, otherCosts).map { type, cost in
                let other = PFObject(className:"Other")
                other.setObject(PFUser.currentUser()!.objectId!, forKey: "userId")
                other.setObject(type, forKey: "otherName")
                other.setObject("\(cost)", forKey: "otherCost")
                return other
            }
    
            PFObject.saveAllInBackground(others) { (success, error) in
                if error == nil {
                    print("Success")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherTypes")
                    NSUserDefaults.standardUserDefaults().setObject(nil, forKey: "otherCosts")
                } else {
                    print("Fail")
                }
            }
    }
    

    【讨论】:

    • 另外,请注意,如所写,当第一个值成功保存时,您的代码将清除整个 otherTypes 和 otherCosts 数组。
    • PaulW11 的回答对于这种情况来说已经足够了。我很欣赏多种不同的处理方式,并为我提供了未来的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 2021-05-02
    • 2020-07-02
    • 1970-01-01
    相关资源
    最近更新 更多