Я создаю приложение, которое использует 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"))
}
@CvEijk Какую информацию вы хотите сохранить. Можете ли вы быть более конкретным, чтобы я мог помочь
Более простым вариантом было бы собрать весь код, который обновляет пользовательский интерфейс с информацией о пользователе в контроллере представления, в один единственный метод, поэтому, когда вы сохраняете пользовательские данные, просто вызывайте этот единственный метод. Что-то похожее на tableView.reloadData()
@JoakimDanielson Ему нужно что-то для обновления просмотров. Это просто настройка наблюдателей, как вы упомянули, и обновление просмотров уведомлений. Но нужно ли ему больше. В этом случае следует использовать лучшую систему кэширования. Кстати, и то, и другое будет легко реализовать. Нам нужно выполнить его требование
Я хочу сохранить несколько изображений для каждого пользователя, данные их учетной записи и некоторую историю использования приложения. Так что не так уж много на самом деле, возможно, некоторые замечания
@AakashDave Я думаю, вы слишком много читаете в этом вопросе.
@JoakimDanielson, можешь объяснить?
@CvEijk, так это все тот же пользователь или есть еще?
@AakashDave Приложение должно иметь информацию только для текущего пользователя, вошедшего в систему. В Firebase, конечно, хранится больше пользователей. Но в приложении только текущий.
@JoakimDanielson Я пытаюсь создать глобальный метод, который обновляет все поля, содержащие пользовательские данные, но у меня возникают проблемы с обновлением разрешений из разных классов, как мне добраться до/обновить их в этой функции?
Вы не можете обновлять разные контроллеры представления из одного места, вам нужен один метод updateUI
в каждом контроллере представления. Я также рекомендую вам переместить фактическое обновление, например, текста метки из let
Извините, перезагрузка — это то, на чем я должен сосредоточиться? мне придется перезагружать все представления в приложении? Или я могу просто перезагрузить определенные элементы?
@CvEijk, на самом деле вы можете это сделать, где бы вы ни обновлялись, у вас будет только одно представление, верно? Вам просто нужно обновить просмотры. Это супер возможно. Перезагружать данные бесполезно. Вам нужно создать способ обновить их. скоро опубликую ответ
@CvEijk просто подтвердите со мной, чтобы я мог сообщить вам
@AakashDave У меня есть 4 представления в tabbarcontroller, но только одно представление, в котором я меняю пользовательские данные да
Ладно, будет тебе :)
@CvEijk Я обновил подробный ответ с объяснением. Я лично реализую это и работает как шарм. Дайте мне знать, если есть сомнения. Если вы удовлетворены, примите и проголосуйте, братан. Ваше здоровье!
Здоровья, приятель! Рад помочь
@AakashDave это слишком долго беспокоило меня, ха-ха, спасибо, что нашли время и силы, чтобы поделиться своим ноу-хау, очень ценно :)
Так что вам придется сначала организовать вещи. В новом файле определите константы, как показано ниже. Эти константы будут доступны в глобальной области видимости, если только 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)
ВАЖНАЯ ЗАМЕТКА --
Всегда не забывайте их инициализировать. Вы можете сделать это, когда пользователь зарегистрируется. Как только они заполнят свои данные и нажмут «Отправить», просто сохраните их в этих переменных. Это не вызовет ненужного сбоя.
Вам придется сохранять их в каждом месте, где вы выполняете обновления, касающиеся этих узлов в базе данных.
Теперь, часть освежающих представлений. Я использую сценарий, в котором ваш 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 = ""`
Это создаст для вас безопасную среду, и вы хорошо настроены.
Это похоже на тот случай, когда вам нужно реализовать паттерн Observable с помощью уведомлений, чтобы при сохранении новых/обновленных данных другие части вашего приложения получали уведомления об этом и могли обновлять себя. См., например, эта статья