Edited at

【Swift5.0】UserDefaultsでパラメータを保存する~iOSアプリ開発入門~


はじめに

こちらの記事は、下記の記事のUIを変更していく過程を記載しています。

【Swift】Firebase Realtime Database を用いてチャットアプリを爆速コーディングしてみた。


この記事で分かること


  • UserDefaultsを使用した値の保存方法


スタート時のソースコード


ViewController.swift

import UIKit

import FirebaseDatabase

class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameInputView: UITextField!
@IBOutlet weak var messageInputView: UITextField!
@IBOutlet weak var inputViewBottomMargin: NSLayoutConstraint!

var databaseRef: DatabaseReference!

override func viewDidLoad() {
super.viewDidLoad()

readData()

addKeyboardShowHideObserver()

}

private func readData() {
databaseRef = Database.database().reference()

databaseRef.observe(.childAdded, with: { snapshot in
dump(snapshot)
if let obj = snapshot.value as? [String : AnyObject], let name = obj["name"] as? String, let message = obj["message"] {
let currentText = self.textView.text
self.textView.text = (currentText ?? "") + "\n\(name) : \(message)"
}
})
}

private func addKeyboardShowHideObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}

@IBAction func tappedSendButton(_ sender: Any) {
view.endEditing(true)

if let name = nameInputView.text, let message = messageInputView.text {
let messageData = ["name": name, "message": message]
databaseRef.childByAutoId().setValue(messageData)

messageInputView.text = ""
}
}

@objc func keyboardWillShow(_ notification: NSNotification){
if let userInfo = notification.userInfo, let keyboardFrameInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
inputViewBottomMargin.constant = keyboardFrameInfo.cgRectValue.height
}

}

@objc func keyboardWillHide(_ notification: NSNotification){
inputViewBottomMargin.constant = 0
}

}



1. ViewControllerにTextFieldのイベントを検知する権限を移譲する

ViewController.swiftの末尾に以下を追加。


ViewController.swift

extension ViewController: UITextFieldDelegate {

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
}


ViewDidLoad()内に以下を記載


ViewController.swift

nameInputView.delegate = self



ViewController.swift

    override func viewDidLoad() {

super.viewDidLoad()

readData()

addKeyboardShowHideObserver()

nameInputView.delegate = self

}


これで、UITextFieldが持つイベントをViewControllerで拾うことができるようになりました。

ちなみに、textFieldShouldReturnメソッドはUITextFieldの入力でEnterが押された事を検知するイベントです。


2. UserDefaultsのインスタンスを生成


ViewController.swift

let userDefaults = UserDefaults.standard



ViewController.swift

class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameInputView: UITextField!
@IBOutlet weak var messageInputView: UITextField!
@IBOutlet weak var inputViewBottomMargin: NSLayoutConstraint!

var databaseRef: DatabaseReference!

let userDefaults = UserDefaults.standard

override func viewDidLoad() {
super.viewDidLoad()

readData()



3. Enterが押されたタイミングでUserDefaultsに値を保存


ViewController.swift

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

guard let inputText = textField.text else {
return true
}
userDefaults.set(inputText, forKey: "name")
userDefaults.synchronize()

return true
}



4. UserDefaultsから値を読み込む


ViewController.swift

    fileprivate func readNameData() -> String {

return userDefaults.object(forKey: "name") as? String ?? ""
}


5. 読み込んだ値をUITextFieldに表示


ViewController.swift

nameInputView.text = readNameData()


これで完了!


6. 完成形のソースがこちら


ViewController.swift

import UIKit

import FirebaseDatabase

class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameInputView: UITextField!
@IBOutlet weak var messageInputView: UITextField!
@IBOutlet weak var inputViewBottomMargin: NSLayoutConstraint!

var databaseRef: DatabaseReference!

let userDefaults = UserDefaults.standard

override func viewDidLoad() {
super.viewDidLoad()

readData()

addKeyboardShowHideObserver()

nameInputView.delegate = self
nameInputView.text = readNameData()

}

private func readData() {
databaseRef = Database.database().reference()

databaseRef.observe(.childAdded, with: { snapshot in
dump(snapshot)
if let obj = snapshot.value as? [String : AnyObject], let name = obj["name"] as? String, let message = obj["message"] {
let currentText = self.textView.text
self.textView.text = (currentText ?? "") + "\n\(name) : \(message)"
}
})
}

private func addKeyboardShowHideObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}

@IBAction func tappedSendButton(_ sender: Any) {
view.endEditing(true)

if let name = nameInputView.text, let message = messageInputView.text {
let messageData = ["name": name, "message": message]
databaseRef.childByAutoId().setValue(messageData)

messageInputView.text = ""
}
}

@objc func keyboardWillShow(_ notification: NSNotification){
if let userInfo = notification.userInfo, let keyboardFrameInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
inputViewBottomMargin.constant = keyboardFrameInfo.cgRectValue.height
}

}

@objc func keyboardWillHide(_ notification: NSNotification){
inputViewBottomMargin.constant = 0
}

fileprivate func readNameData() -> String {
return userDefaults.object(forKey: "name") as? String ?? ""
}

}

extension ViewController: UITextFieldDelegate {

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard let inputText = textField.text else {
return true
}
userDefaults.set(inputText, forKey: "name")
userDefaults.synchronize()

return true
}
}



7. リファクタリング


  • Keyの定数化

  • 保存処理をメソッド化

  • 保存処理をボタン押下時にも追加


ViewController.swift

import UIKit

import FirebaseDatabase

class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameInputView: UITextField!
@IBOutlet weak var messageInputView: UITextField!
@IBOutlet weak var inputViewBottomMargin: NSLayoutConstraint!

var databaseRef: DatabaseReference!

let userDefaults = UserDefaults.standard
fileprivate let nameKey = "name"
fileprivate let messageKey = "message"

override func viewDidLoad() {
super.viewDidLoad()

readData()

addKeyboardShowHideObserver()

nameInputView.delegate = self
nameInputView.text = readNameData()

}

private func readData() {
databaseRef = Database.database().reference()

databaseRef.observe(.childAdded, with: { snapshot in
dump(snapshot)
if let obj = snapshot.value as? [String : AnyObject], let name = obj[self.nameKey] as? String, let message = obj[self.messageKey] {
let currentText = self.textView.text
self.textView.text = (currentText ?? "") + "\n\(name) : \(message)"
}
})
}

private func addKeyboardShowHideObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}

@IBAction func tappedSendButton(_ sender: Any) {
view.endEditing(true)

if let name = nameInputView.text, let message = messageInputView.text {
save(name: name)

let messageData = [nameKey: name, messageKey: message]
databaseRef.childByAutoId().setValue(messageData)

messageInputView.text = ""
}
}

@objc func keyboardWillShow(_ notification: NSNotification){
if let userInfo = notification.userInfo, let keyboardFrameInfo = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
inputViewBottomMargin.constant = keyboardFrameInfo.cgRectValue.height
}

}

@objc func keyboardWillHide(_ notification: NSNotification){
inputViewBottomMargin.constant = 0
}

fileprivate func readNameData() -> String {
return userDefaults.object(forKey: nameKey) as? String ?? ""
}

fileprivate func save(name: String) {
userDefaults.set(name, forKey: nameKey)
userDefaults.synchronize()
}

}

extension ViewController: UITextFieldDelegate {

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard let inputText = textField.text else {
return true
}
save(name: inputText)

return true
}
}



GitHubはこちら

https://github.com/Tetsukick/Firebase-chat-iOS