Swift UITableViewController `await`, пока все данные не будут загружены перед рендерингом, или повторно выполнить рендеринг после загрузки данных - PullRequest
1 голос
/ 25 апреля 2020

Я на Swift 4. Цель состоит в том, чтобы загрузить все данные в адресную книгу, прежде чем отобразить адресную книгу. На другом языке, например js, я могу использовать await в каждом элементе в l oop, прежде чем указывать представлению визуализировать строки. Я ищу канонический способ решения этой проблемы в Swift 4 с помощью UITableViewController.

. Сейчас адресная книга хранится в бэкэнде с Amplify и GraphQL. У меня есть User модель формы

type User @Model {
  id: ID!
  name: String!
  bio : String!
}

и Contact формы

type Contact @model {
  ownerId: ID!
  userId: ID!
  lastOpened: String
}

В ContactController: UITableViewController.viewDidLoad Я получаю все Contact в базе данных, где ownerId id-токен моего пользователя, затем я создаю объект, используя эту contact информацию. И затем для каждого Contact экземпляра объекта я получаю соответствующий User в базе данных при инициализации объекта. В этом сообщении: Подождите, пока swift для l oop с асинхронными сетевыми запросами не завершит выполнение , я использую группу Dispatch, а затем перезагрузите UITableView после завершения l oop и Dispatch группа закончилась. Но когда я print утешаю, я вижу, что l oop завершается до того, как объект Contact загрузил свою User информацию.

Фрагменты кода:

class ContactsController: UITableViewController, UISearchResultsUpdating {

        var dataSource : [Contact] = []


        override func viewDidLoad() {

            super.viewDidLoad()

            let fetchContactGrp = DispatchGroup()

            fetchContactGrp.enter()

            self.getMyContacts(){ contacts in

                for contact in contacts {

                    let _contactData = Contact(
                          userId     : contact.userId
                        , contactId  : contact.id
                        , timeStamp  : contact.timeStamp
                        , lastOpened : contact.lastOpened
                        , haveAccount: true
                    )

                    _contactData.loadData()
                    self.dataSource.append(_contactData)
                }

            }


            fetchContactGrp.leave()

            DispatchQueue.main.async{
                 self.tableView.reloadData()
            }
        }

    }

Функция self.getMyContacts - это просто стандартный запрос GraphQL:

func getMyContacts( callBack: @escaping ([Contact]) -> Void ){

    let my_token = AWSMobileClient.default().username
    let contact = Contact.keys
    let predicate = contact.ownerId == my_token! 

    _ = Amplify.API.query(from: Contact.self, where: predicate) { (event) in
        switch event {
            case .completed(let result):
                switch result {
                    case .success(let cts):
                        /// @On success, output a user list
                        callBack(cts)
                    case .failure(let error):
                        break
                }
            case .failed(let error):
                break
            default:
                break
        }
    }
}

И объект Contact загружает данные User из базы данных:

class Contact {

        let userId: String!
        let contactId: String!

        var name : String
        var bio  : String
        var website: String

        let timeStamp: String
        let lastOpened: String


        init( userId: String, contactId: String, timeStamp: String, lastOpened: String, haveAccount: Bool){

            self.userId     = userId
            self.contactId  = contactId
            self.timeStamp  = timeStamp
            self.lastOpened = lastOpened
            self.haveAccount = haveAccount


            self.name = ""
            self.bio  = ""
            self.website = ""

        }

        func loadData(){

            /// @use: fetch user data from db and populate field on initation
            let _ = Amplify.API.query(from: User.self, byId: self.userId) { (event) in

                switch event {
                    case .completed(let res):
                        switch res{
                            case .success (let musr):
                                if (musr != nil){

                                    let userData = musr!
                                    let em    = genEmptyString()
                                    self.name = (userData.name == em) ? "" : userData.name
                                    self.bio  = (userData.bio == em)  ? "" : userData.bio
                                    self.website = (userData.website == em) ? "" : userData.website

                                    print(">> amplify.query: \(self.name)")

                                } else {
                                    break
                                }
                            default:
                               break
                        }
                    default:
                        print("failed")
                }
            }
        }


    }

Ответы [ 2 ]

0 голосов
/ 26 апреля 2020
0 голосов
/ 25 апреля 2020

Это потому, что функция getMyContacts () выполняет задачу Asyn c, и элемент управления переходит к ней и выполняет инструкцию выхода. Вам нужно вызвать оператор выхода внутри функции getMyContacts () вне функции for l oop.

Попробуйте следующий код:

override func viewDidLoad() {

            super.viewDidLoad()

            let fetchContactGrp = DispatchGroup()

            fetchContactGrp.enter()

            self.getMyContacts(){ contacts in

                for contact in contacts {

                    let _contactData = Contact(
                          userId     : contact.userId
                        , contactId  : contact.id
                        , timeStamp  : contact.timeStamp
                        , lastOpened : contact.lastOpened
                        , haveAccount: true
                    )

                    _contactData.loadData()
                    self.dataSource.append(_contactData)
                }
                fetchContactGrp.leave()
            }


            fetchContactGrp.wait()

            DispatchQueue.main.async{
                 self.tableView.reloadData()
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...