User Defaults 만들기

Singleton 디자인 패턴 실습

UserDefaults와 유사한 싱글톤 객체, DataCenter 만들기

Xcode Project Files

Singletone Design Pattern

👌🏻 01. User Model Struct 설계

import Foundation
struct UserModel {

    enum Gender: Int {
        case women = 1
        case men = 2
    }
    
    var userID: String
    var userPWD: String
    var email: String
    var birthday: String
    var gender: Gender?
    var dictionary:[String:Any] {
        let genderValue = self.gender?.rawValue ?? 0
        let dic:[String:Any] = ["userID":self.userID, "userPWD":self.userPWD, "email":self.email, "gender":genderValue]
        return dic
    }
    
    init?(userDic:[String:Any]) {
        
        // Required Properties
        guard let userID = userDic["userID"] as? String else { return nil }
        self.userID = userID
        
        guard let userPWD = userDic["userPWD"] as? String else { return nil }
        self.userPWD = userPWD
        
        guard let email = userDic["email"] as? String else { return nil }
        self.email = email
        
        guard let birthday = userDic["birthday"] as? String else { return nil }
        self.birthday = birthday
        
        // Optional Properties
        if let gender = userDic["gender"] as? Int, (gender == 1 || gender == 2)
        {
            self.gender = Gender(rawValue: gender)
        }
        
    }
    
}

👌🏻 02. Data Center 설계하기

import Foundation
class DataCenter
{
    // Singleton Instance (shared Instance)
    static var main: DataCenter = DataCenter()
    var currentUser: UserModel?
    
    private init() {
        loadUserData()
    }
    
    func object(forkey: String) -> Any? {
        let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/UserPlist.plist"
        guard let documentDic = NSDictionary(contentsOfFile: documentPath) as? [String:Any] else { return nil }
        return documentDic[forkey]
    }
    
    // 최초에는 documentPath에 plist 파일이 없으므로 currentUser가 nil인 상태
    // 다시 로그인 할 떄는 AppDelegate에서 Background로 진입할 때 writeUserData() 하면서 documentPath에 plist 파일을 생성하므로, init할 때 loadUserData()를 하면서 currentUser가 생김
    
    func loadUserData() {
        // document Path는 String의 array로 들어오기 때문에, [0] + 내 파일명
        let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/UserPlist.plist"
        guard let documentDic = NSDictionary(contentsOfFile: documentPath) as? [String:Any] else { return }
        currentUser = UserModel(userDic: documentDic)
    }
    
    func writeUserData() -> Bool {
        let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/UserPlist.plist"
        guard let data = currentUser else { return false }
        let newDic = data.dictionary
        let NSDic = NSDictionary(dictionary: newDic)
        NSDic.write(toFile: documentPath, atomically: true)
        return true
    }
}

👌🏻 03. ViewController에서 DataCenter 사용

import UIKit
class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // DataCenter
        if let _ = DataCenter.main.currentUser {
            // main 화면을 띄운다.
        }else {
            // 로그인 화면을 띄운다.
            // 사용자가 최초 로그인 -> 로그인 정보를 newUserDic으로 만들어서
            let newUserDic = ["userID":"","userPWD":"","email":""]
            DataCenter.main.currentUser = UserModel(userDic: newUserDic)
        }
    }

}

👌🏻 04. Write Data

func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    
    let isSaved = DataCenter.main.writeUserData()
    print(isSaved)
}