同时查询解析服务器和本地数据存储

时间:2015-05-05 14:14:21

标签: swift parse-platform

我正在尝试创建一个PFQuery,其中查询的响应存储在服务器和本地数据存储中。我想用约束(query.whereKey())创建一个查询,它将首先查看响应是否存储在设备上,如果没有,它将查询服务器。

例如,我正在加载帖子列表。该应用程序存储当前用户正在关注的一组用户。对于存储在设备上的用户发布的帖子,我想从数据存储区而不是服务器加载用户详细信息(如他们的个人资料图片和用户名)。但是,如果帖子由未存储在设备上的用户发布,则它将查询服务器。我只能想象这有两个不同的查询,但我更愿意在一个查询中进行。

2 个答案:

答案 0 :(得分:2)

我在自己的项目中写了以下内容,并发布了以防任何人正在寻找完整的答案。

参数如下:

  1. query:您要执行查询的PFQuery
  2. queryBothBool值,如果有本地数据存储返回的数据,是否要查询Parse服务器。 true将查询两者,false仅在本地数据存储中未返回任何内容时才会查询服务器。
  3. toCallUponCompletion:从服务器,本地数据存储或两者接收响应时将调用的闭包(函数)。该函数应接受PFObjects数组并且不返回任何内容。此功能的实现将在以下功能下面显示。
  4. 功能:

    func findObjectsInBackgroundFromLocalDataStoreIfPossible (query: PFQuery, queryBoth: Bool, toCallUponCompletion: ([PFObject]) -> ()){
        var response = [PFObject]()
    
        let queryCopy = query.copy() as! PFQuery
        queryCopy.fromLocalDatastore()
        queryCopy.findObjectsInBackgroundWithBlock{
            (objects: [AnyObject]?, error: NSError?) -> Void in
            if error == nil{
                if objects?.count == 0{
                    query.findObjectsInBackgroundWithBlock{
                         (objects2: [AnyObject]?, error: NSError?) -> Void in
                        if error == nil{
                            response = objects2 as! [PFObject]
                            toCallUponCompletion(response)
                        }
                    }
                }
                else if queryBoth{
                    response = objects as! [PFObject]
                    var responseObjectIds = [String]()
                    for x in response{
                        responseObjectIds.append(x.objectId)
                    }
                    query.whereKey("objectId", notContainedIn: responseObjectIds)
                    query.findObjectsInBackgroundWithBlock{
                        (objects2: [AnyObject]?, error: NSError?) -> Void in
                        if error == nil{
                            response += objects2 as! [PFObject]
                            toCallUponCompletion(response)
                        }
                        else{
                            toCallUponCompletion(response)
                        }
                    }
                }
                else{
                    response = objects as! [PFObject]
                    toCallUponCompletion(response)
                }
            }
            else{
                println("Error being called in 'findObjectInBackgroundFromLocalDataStoreIfPossible' Error is: \(error)")
            }
        }
    }
    

    关闭实施:

    func storeResponse (response: [PFObject]){
        println(response)
    }
    

    要实现与上述功能相同的功能,但使用多个PFQueries,请使用以下命令:

    参数不同如下:

    1. queries:这是您要执行查询的PFQueries数组。订单很重要。
    2. toCallUponCompletion:此闭包使用带有Int个键和PFObject值的字典作为参数,并且不返回任何内容。这样做的原因是因为在发送查询时,它们可能无法完成并以相同的顺序返回。因此,字典中每个键值对的关键是它发送的顺序,因此可以在不知道响应的实际内容的情况下使用响应。再次,请参阅函数后面的函数闭包的实现。
    3. 功能:

      func findObjectsInBackgroundFromMultipleQueriesFromLocalDataStoreIfPossible (queries: [PFQuery], queryBoth: Bool, toCallUponCompletion: ([Int: [PFObject]]) -> ()){
          var responses = [Int: [PFObject]]()
          for query in queries{
              var response = [PFObject]()
              let queryCopy = query.copy() as! PFQuery
              queryCopy.fromLocalDatastore()
              queryCopy.findObjectsInBackgroundWithBlock{
                  (objects: [AnyObject]?, error: NSError?) -> Void in
                  if error == nil{
                      if objects?.count == 0{
                          query.findObjectsInBackgroundWithBlock{
                              (objects2: [AnyObject]?, error: NSError?) -> Void in
                              if error == nil{
                                  response = objects2 as! [PFObject]
                                  responses[find(queries, query)!] = response  
                                  if responses.count == queries.count{
                                      toCallUponCompletion(responses)
                                  }
                              }
                          }
                      }
                      else if queryBoth{
                          response = objects as! [PFObject]
                          var ids = [String]()
                          for x in response{
                              ids.append(x.objectId)
                          }
                          query.whereKey("objectId", notContainedIn: ids)
                          query.findObjectsInBackgroundWithBlock{
                              (objects2: [AnyObject]?, error: NSError?) -> Void in
                              if error == nil{
                                  response += objects2 as! [PFObject]
                                  responses[find(queries, query)!] = response
                                  if responses.count == queries.count{
                                      toCallUponCompletion(responses)
                                  }
                               }
                           }
                       }
                       else{
                           response = objects as! [PFObject]
                           responses[find(queries, query)!] = response
                           if responses.count == queries.count{
                               toCallUponCompletion(responses)
                           }
                      }
                  }
              }
          }
      }
      

      关闭实施:

      func storeResponses (responses: [Int: PFObject]){
          println("The response to the first query is: \(responses[0])")
          println("The response to the second query is: \(responses[1])")
          println("The response to the third query is: \(responses[2])")
      }
      

      非常感谢任何编辑建议。

答案 1 :(得分:0)

Parse对fromLocalDatastore有一个PFQuery方法,但我不知道notFromLocalDatastore方法...我唯一能想到的是制作一个新的方法创建查询,然后你可以调用:

userQuery().fromLocalDatastore().getFirstObjectInBackgroundWithBlock { localR in
    if let user = localR {
        //use the user
    } else {
        userQuery().getFirstObjectInBackgroundWithBlock { serverR
            if let user = serverR {
                //user the user
            } else {
                //not even on server - handle somehow...
            }
        }
    }
}