Глобальное кэширование данных сервера и обновление представлений

Я создаю приложение, которое использует firebase для аутентификации и функциональности базы данных. Как только пользователь регистрируется, для этого пользователя сохраняется запись в базе данных, содержащая некоторую основную информацию, такую ​​как имя, фамилия и т. д.

Как только пользователь входит в систему со своими учетными данными, я хочу установить глобальную переменную (возможно, userDefaults?), Которая содержит пользовательские данные для этого конкретного пользователя. В противном случае мне придется извлекать пользовательские данные каждый раз, когда я хочу заполнить метку, например, именем пользователя.

Мне удалось установить пользовательские значения по умолчанию при входе в систему и использовать эту информацию в UIlables. Но когда я позволяю пользователям вносить изменения в свои данные, некоторые из которых важны для функционирования приложения, я могу обновить сервер И пользовательские настройки по умолчанию, но само приложение не обновляется с правильными данными. Он сохраняет старые данные (например) в UIlables.

Я хотел бы получить больше информации о том, какой рабочий процесс лучше всего подходит для управления такими ситуациями.

При открытии приложения у меня tabBarController установлено как rootviewcontroller. В загрузке tabbarcontroller у меня есть следующий код, извлекающий пользовательские данные из firebase и сохраняющий их в userdefaults:

guard let uid = Auth.auth().currentUser?.uid else { return }
            Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
                print(snapshot.value ?? "")


              guard let dictionary = snapshot.value as? [String: Any] else { return }
                let firstname = dictionary["First name"] as? String
                let lastname = dictionary["Last name"] as? String

                print("first name is: " + firstname!)

                UserDefaults.standard.set(firstname, forKey: "userFirstName")

                print(UserDefaults.standard.value(forKey: "userFirstName"))


                self.setupViewControllers()


            }

Затем я продолжаю загружать все контроллеры представления в tabBarController:

self.setupViewControllers()

Во время этого процесса метки в этих контроллерах представления заполняются данными пользователя по умолчанию.

Это пример метки, заполненной пользовательскими значениями по умолчанию, но не обновляемой при изменении пользовательских значений по умолчанию:

    let welcomeLabel: UILabel = {
        let label = UILabel()  
        let attributedText = NSMutableAttributedString(string: "Welcome ")
        attributedText.append(NSAttributedString(string: "\(UserDefaults.standard.string(forKey: "userFirstName")!)"))
        label.attributedText = attributedText
        label.font = UIFont.systemFont(ofSize: 30, weight: .bold)
        return label
    }()

это функция, которую я использую для обновления имени (через текстовое поле, заполненное пользователем):

    @objc func updateName() {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        Database.database().reference().child("users").child(uid).updateChildValues(["First name" : updateNameField.text ?? ""])

        UserDefaults.standard.set(updateNameField.text, forKey: "userFirstName")

        print(UserDefaults.standard.value(forKey: "userFirstName"))
    }

Это похоже на тот случай, когда вам нужно реализовать паттерн Observable с помощью уведомлений, чтобы при сохранении новых/обновленных данных другие части вашего приложения получали уведомления об этом и могли обновлять себя. См., например, эта статья

Joakim Danielson 30.05.2019 09:06

@CvEijk Какую информацию вы хотите сохранить. Можете ли вы быть более конкретным, чтобы я мог помочь

Aakash Dave 30.05.2019 09:14

Более простым вариантом было бы собрать весь код, который обновляет пользовательский интерфейс с информацией о пользователе в контроллере представления, в один единственный метод, поэтому, когда вы сохраняете пользовательские данные, просто вызывайте этот единственный метод. Что-то похожее на tableView.reloadData()

Joakim Danielson 30.05.2019 09:16

@JoakimDanielson Ему нужно что-то для обновления просмотров. Это просто настройка наблюдателей, как вы упомянули, и обновление просмотров уведомлений. Но нужно ли ему больше. В этом случае следует использовать лучшую систему кэширования. Кстати, и то, и другое будет легко реализовать. Нам нужно выполнить его требование

Aakash Dave 30.05.2019 09:19

Я хочу сохранить несколько изображений для каждого пользователя, данные их учетной записи и некоторую историю использования приложения. Так что не так уж много на самом деле, возможно, некоторые замечания

CVE 30.05.2019 09:20

@AakashDave Я думаю, вы слишком много читаете в этом вопросе.

Joakim Danielson 30.05.2019 09:23

@JoakimDanielson, можешь объяснить?

Aakash Dave 30.05.2019 09:24

@CvEijk, так это все тот же пользователь или есть еще?

Aakash Dave 30.05.2019 09:25

@AakashDave Приложение должно иметь информацию только для текущего пользователя, вошедшего в систему. В Firebase, конечно, хранится больше пользователей. Но в приложении только текущий.

CVE 30.05.2019 09:26

@JoakimDanielson Я пытаюсь создать глобальный метод, который обновляет все поля, содержащие пользовательские данные, но у меня возникают проблемы с обновлением разрешений из разных классов, как мне добраться до/обновить их в этой функции?

CVE 30.05.2019 09:27

Вы не можете обновлять разные контроллеры представления из одного места, вам нужен один метод updateUI в каждом контроллере представления. Я также рекомендую вам переместить фактическое обновление, например, текста метки из let

Joakim Danielson 30.05.2019 09:28

Извините, перезагрузка — это то, на чем я должен сосредоточиться? мне придется перезагружать все представления в приложении? Или я могу просто перезагрузить определенные элементы?

CVE 30.05.2019 09:29

@CvEijk, на самом деле вы можете это сделать, где бы вы ни обновлялись, у вас будет только одно представление, верно? Вам просто нужно обновить просмотры. Это супер возможно. Перезагружать данные бесполезно. Вам нужно создать способ обновить их. скоро опубликую ответ

Aakash Dave 30.05.2019 09:30

@CvEijk просто подтвердите со мной, чтобы я мог сообщить вам

Aakash Dave 30.05.2019 09:32

@AakashDave У меня есть 4 представления в tabbarcontroller, но только одно представление, в котором я меняю пользовательские данные да

CVE 30.05.2019 09:38

Ладно, будет тебе :)

Aakash Dave 30.05.2019 09:42

@CvEijk Я обновил подробный ответ с объяснением. Я лично реализую это и работает как шарм. Дайте мне знать, если есть сомнения. Если вы удовлетворены, примите и проголосуйте, братан. Ваше здоровье!

Aakash Dave 30.05.2019 10:20

Здоровья, приятель! Рад помочь

Aakash Dave 30.05.2019 10:45

@AakashDave это слишком долго беспокоило меня, ха-ха, спасибо, что нашли время и силы, чтобы поделиться своим ноу-хау, очень ценно :)

CVE 30.05.2019 10:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
19
126
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Так что вам придется сначала организовать вещи. В новом файле определите константы, как показано ниже. Эти константы будут доступны в глобальной области видимости, если только private

Константы.swift

private let storedusername = "usname"
    private let storedName = "uname"
    private let displaypic = "udp"
    private let aboutme = "udesc"

    var myusername : String {
        get {
            return (UserDefaults.standard.string(forKey: storedusername)!)
        } set {
            UserDefaults.standard.set(newValue, forKey: storedusername)
        }
    }

    var myname : String {
        get {
            return (UserDefaults.standard.string(forKey: storedName)!)
        } set {
            UserDefaults.standard.set(newValue, forKey: storedName)
        }
    }

    var myProfileImage : Data {
        get {
            return (UserDefaults.standard.data(forKey: displaypic)!)
        } set {
            UserDefaults.standard.set(newValue, forKey: displaypic)
        }
    }

    var myAboutMe : String? {
        get {
            return (UserDefaults.standard.string(forKey: aboutme)!)
        } set {
            UserDefaults.standard.set(newValue, forKey: aboutme)
        }
    }

Теперь в следующий раз, когда вы захотите что-то сохранить в UserDefaults, вы просто сделаете следующее в любом месте своей базы кода:

myusername = "@CVEIjk"

И чтобы получить его, просто вызовите его:

print(myusername)

ВАЖНАЯ ЗАМЕТКА --

  1. Всегда не забывайте их инициализировать. Вы можете сделать это, когда пользователь зарегистрируется. Как только они заполнят свои данные и нажмут «Отправить», просто сохраните их в этих переменных. Это не вызовет ненужного сбоя.

  2. Вам придется сохранять их в каждом месте, где вы выполняете обновления, касающиеся этих узлов в базе данных.

Теперь, часть освежающих представлений. Я использую сценарий, в котором ваш ProfileView.swift имеет представление, а пользователь переходит к EditProfile.swift для обновления контента.

Вы инициализируете всех своих наблюдателей в том месте, где обновление будет иметь немедленный эффект. Потому что вид сразу после обновления имеет значение. Остальные будут вызываться через геттер aboutme

ProfileView.swift

func openEditView() {

        NotificationCenter.default.addObserver(self, selector: #selector(fetchUserDetails), name: Notification.Name("update"), object: nil)

        //setting this right before the segue will create an observer specifically and exclusively for updates. Hence you don't have to worry about the extra observers.

        perform(segue: With Identifier:)// Goes to the editProfile page
    }

Первоначально эта функция будет вызываться в viewDidLoad(). В это время вам нужно убедиться, что у вас есть все данные, иначе они не будут давать никаких значений. Но если вы сохраняете все по мере регистрации пользователя, вы в безопасности.

@objc func fetchUserDetails() {
        if uid != nil {
            if myname.count > 0 { // This will check if the variable has anything in the memory or not. Dont confuse this with [Array].count
                self.nameLabel = myname
            }
        }
    }

Эта функция также действует как метод аб-наблюдателя. Поэтому, когда уведомления публикуются, они могут запускаться снова.

Теперь EditProfile.swift

В блоке, где вы обновляете сервер, сохраните значения, а затем создайте Notification.post и поместите этот метод прямо перед собой dismiss(toViewController:)

   func updateUserCacheData(name: String, username: String, aboutme: String, ProfilePhoto: UIImage? = nil) {
        DispatchQueue.global().async {
            myname = name
            myusername = username
            myAboutMe = aboutme
            if self.newImage != nil {
                myProfileImage = self.newImage!.jpegData(compressionQuality: 1)!
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: .refreshProfileViews, object: nil)
            }
        }
    }

    func updateToServerAndBackToProfileView() {
        self.updateUserCacheData(name: iname!, username: iusername, aboutme: iaboutme!)
        self.dismiss(animated: true, completion: nil)
        }
    }

Пока это возвращается к ProfileView, ваши просмотры будут мгновенно обновлены. Вы можете оставить наблюдателя, где бы вы ни смотрели, он будет отображаться первым после закрытия. остальные всегда будут получать обновленный контент. Также не забудьте deinit своего Наблюдателя в ProfileView

//This code is in ProfileView.swift
deinit {
        NotificationCenter.default.removeObserver(self, name: Notification.Name("update"), object: nil)
    }

Кроме того, в случаях, когда содержимое может быть пустым, просто инициализируйте его пустым содержимым. Например, если пользователь не хочет добавлять информацию обо мне при регистрации, вы можете просто указать

`myaboutme = ""`

Это создаст для вас безопасную среду, и вы хорошо настроены.

Другие вопросы по теме