【问题标题】:AWS Amplify - sync DataStoreAWS Amplify - 同步数据存储
【发布时间】:2020-10-19 16:12:00
【问题描述】:

我正在尝试构建一个原型应用程序来评估 AWS-Amplify (DataStore) 在我们的下一个应用程序中的使用。尝试同步 2 个客户端时遇到问题。我按照此处教程的说明设置了我的 AWS-DataStore:https://docs.amplify.aws/lib/datastore/getting-started/q/platform/ios 使用 Cocoapods。关于 Cocoapods 一切都按预期工作。我尝试了一些测试,也可以在上面的“操纵数据”链接下看到。我还做了“将数据同步到云”部分。我可以在 AWS 控制台的 dynamoDB 中查看我的数据。当我添加一个条目时,我可以在控制台中看到它一切都按预期工作,但在两种情况下我遇到了问题:

假设我有 2 个客户端 A 和 B(都运行 iOS 13 - 在这里它是真实设备还是在模拟器上并不重要),我希望这些客户端保持同步。为此,我添加了一个 PostStore(我正在使用来自 atm 上方 AWS 链接的示例架构),如下所示:

import Foundation
import Combine
import SwiftUI
import Amplify

class PostStore: ObservableObject {
    
    @Published private(set) var posts: [Post] = []
    
    var postSubscription: AnyCancellable?
    
    init() {
        self.getAllPostsFromDataStore()
    }
    
    deinit {
        self.unsubscribeFromDataStore()
    }
    
    func getAllPostsFromDataStore() {
        
        Amplify.DataStore.query(Post.self) { (result) in
            switch result {
            case .success(let posts):
                DispatchQueue.main.async {
                    print("Got \(posts.count) Posts from DataStore initially")
                    self.posts = posts
                }
            case .failure(let error):
                print("Error getting Posts from DataStore: \(error.localizedDescription)")
            }
        }
    }
    
    func addRandomPostToDataStore() {
        
        let post = Post.getRandomPost()
        self.addPostToArray(post)
        
        print("Fire: \(post.id)")
        
        Amplify.DataStore.save(post) {
            
            switch $0 {
            case .success(let post):
                print("Added post with id: \(post.id)")
            case .failure(let error):
                print("Error adding post with title: \(post.title) Error: \(error.localizedDescription)")
            }
        }
    }
    
    func deletePostFromDataStore(for indexSet: IndexSet) {
        
        let postsToDelete = indexSet.map { self.posts[$0] }
        
        self.posts.remove(atOffsets: indexSet)
        
        for post in postsToDelete {
            
            Amplify.DataStore.delete(post) { (result) in
                switch result {
                case .success():
                    print("Deleted Post from DataStore")
                case .failure(let error):
                    print("Error deleting Post From DataStore: \(error)")
                }
            }
        }
    }
        
    func subscribeToDataStore() {
        
        postSubscription = Amplify.DataStore.publisher(for: Post.self)
            .sink(receiveCompletion: { (completion) in

                print("Completion!")

                if case .failure(let error) = completion {
                    print("Subscription received Error: \(error.localizedDescription)")
                }

            }, receiveValue: { (changes) in
                
                
                //print("Subscription received mutation: \(changes)")
                print("\n\n\n")
                print("\(try! changes.toJSON())")
                print("\n\n\n")
//                print("Changes!")
                let newPost = try! changes.decodeModel(as: Post.self)

                DispatchQueue.main.async {

                    switch changes.mutationType {
                    case "create":
//                        print("Create Subscription")
                        self.addPostToArray(newPost)
                        break
                    case "update":
                        print("Update Subscription")
                        self.updatePostInArray(newPost)
                        break
                    case "delete":
                        print("Delete Subscription")
                        self.deletePostFromArray(newPost)
                        break
                    default:
                        print("AnotherType?")
                        print(changes.mutationType)
                        break
                    }
                }
                print("\n")
            })
    }
    
    func unsubscribeFromDataStore() {
        postSubscription?.cancel()
    }
    
    private func addPostToArray(_ post: Post) {
        
        if !self.posts.contains(post) {
            self.posts.append(post)
        }
    }
    
    private func deletePostFromArray(_ post: Post) {
        
        if let index = self.posts.firstIndex(of: post) {
            self.posts.remove(at: index)
        }
    }
    
    private func updatePostInArray(_ post: Post) {
        print("update?")
    }
}

subscribeToDataStore 方法是通过 SwiftUI-View(在 onAppear 中)触发的,是这里的关键。如果我向客户端 A(缓慢)添加一些帖子,那么客户端 B 会收到所有更改并将其添加到存储中(我使用 SwiftUI 视图将其可视化,但在本示例中并不重要)。没有问题,一切都按预期工作。

但是

  1. 当我通过客户端 A 快速添加新条目(帖子)时,B 不会获取一些新条目。
  2. 当我在客户端 B 离线(处于飞行模式)时添加超过 1 个条目并且我关闭飞行模式时,每次订阅只会获取最新的条目。

在这两种情况下,当我触发 getAllPostsFromDataStore 时,每个条目都会被提取,我们可以再次进行。

所以我的问题是:为什么订阅没有获取每个条目?

在进行场景 1 时有一个有趣的事实:接收每个订阅条目时的常见日志消息如下所示:

WebsocketDidReceiveMessage - {MyObject}

然后我再次在接收器“receiveValue”完成中记录对象:

{MyObject}

但是当快速(在短时间内)添加一些条目时,来自 Amplify 的日志消息有时看起来像这样:(这是订阅获取中缺少第一个“对象”的地方):

WebsocketDidReceiveMessage - {MyObject}
WebsocketDidReceiveMessage - {MyObject2}

然后我再次在接收器“receiveValue”完成中记录对象,并且只有最后一个对象被记录:

{MyObject2}

似乎{MyObject} 在快速添加多个条目时被取消或发生了什么。如上所述,当 B 处于飞行模式或没有连接时,仅获取最后添加的条目。 (但我也只收到WebsocketDidReceiveMessage 的最后一条日志消息)。

我在这里遗漏了什么还是 Amplify-DataStore SDK 中的错误?

请原谅我的英语不好。我不是母语人士,有时很难准确说出问题所在。如果您对此问题有任何疑问或需要更多信息,请发表评论,我将编辑我的问题,提供您需要的一切。

最好的问候

【问题讨论】:

    标签: ios swift swiftui aws-amplify combine


    【解决方案1】:

    对于同样遇到此问题的任何人:

    我提交了一个问题 here,问题似乎在 1.3.1 版本中通过 PR #756 得到修复

    玩得开心!

    【讨论】:

      猜你喜欢
      • 2022-12-06
      • 2023-01-07
      • 2021-06-04
      • 2022-12-14
      • 2021-09-11
      • 2022-01-03
      • 1970-01-01
      • 2019-04-10
      • 2021-09-12
      相关资源
      最近更新 更多