티스토리 뷰

LoginDataModel.swift

import Foundation

// MARK: - LoginDataModel
struct LoginDataModel: Codable {
    let success: Bool
    let message: String
    let data: UserData?
    
    enum CodingKeys: String, CodingKey {
        case success
        case message
        case data
    }
    
    init(from decoder : Decoder) throws
    {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        success = (try? values.decode(Bool.self, forKey: .success)) ?? false
        message = (try? values.decode(String.self, forKey: .message)) ?? ""
        data = (try? values.decode(UserData.self, forKey: .data)) ?? nil
    }
}

// MARK: - UserData
struct UserData: Codable {
    let userID: Int
    let userNickname, token: String

    enum CodingKeys: String, CodingKey {
        case userID = "UserId"
        case userNickname = "user_nickname"
        case token
    }
}

코드 쪼개기 ..!

let data: UserData?

성공/실패에 따라 data가 있을수도/없을수도 있기 때문에, ?(옵셔널)형으로 data 선언

 

LoginService.swift


import Foundation
import Alamofire

struct LoginService{
    static let shared = LoginService()
    
    private func makeParameter(email : String, password : String) -> Parameters
    {
        return ["email" : email,
                "password" : password]
    }
    
    func login(email : String,
               password : String,
               completion : @escaping (NetworkResult<Any>) -> Void)
    {
        let header : HTTPHeaders = ["Content-Type": "application/json"]
        let dataRequest = AF.request(APIConstants.loginURL,
                                     method: .post,
                                     parameters: makeParameter(email: email, password: password),
                                     encoding: JSONEncoding.default,
                                     headers: header)
        
        
        dataRequest.responseData { dataResponse in
            
            dump(dataResponse)
            
            switch dataResponse.result {
            case .success:
                
                
                guard let statusCode = dataResponse.response?.statusCode else {return}
                guard let value = dataResponse.value else {return}
                let networkResult = self.judgeStatus(by: statusCode, value)
                completion(networkResult)
            
            case .failure: completion(.pathErr)
                
            }
        }
                                            
    }
    
    private func judgeStatus(by statusCode: Int, _ data: Data) -> NetworkResult<Any> {
        
        let decoder = JSONDecoder()
        
        guard let decodedData = try? decoder.decode(LoginDataModel.self, from: data)
        else { return .pathErr}
        
        switch statusCode {
            
        case 200: return .success(decodedData.message)
        case 400: return .requestErr(decodedData.message)
        case 500: return .serverErr
        default: return .networkFail
        }
    }
    

    
}

통신을 해야하는 부분을 작성! 

get했던 방식과 굉장히 유사하다! 바뀐 점 몇가지 체크해보면

1.
 private func makeParameter(email : String, password : String) -> Parameters
    {
        return ["email" : email,
                "password" : password]

GET 방식과는 다르게, POST에서는 body에 데이터를 실어서 요청할 수 있다.

우라기 지금 하고 있는 로그인도 아이디 / 패스워드를 같이 담아서 보내야한다.

아이디, 비밀번호를 매개변수로 받아서 Parameters 형태로 return 하는 함수를 작성하였다.

 

2.
(APIConstants.loginURL, method: .post,
	 parameters: makeParameter(email: email, password: password),

method 는 post로 ! 

GET에서는 parameter를 안 넘겨줬는데, 여기서는 아까 만든 makeParameter를 통해 parameter를 넘긴다!

3.
let decoder = JSONDecoder()
        
        guard let decodedData = try? decoder.decode(LoginDataModel.self, from: data)
        else { return .pathErr}
        
        switch statusCode {
            
        case 200: return .success(decodedData.message)
        case 400: return .requestErr(decodedData.message)
        case 500: return .serverErr
        default: return .networkFail

서버에서 주는 값 중에서 message만 빼서 밖으로 전달!

이 메세지를 가지고 밖에서 UIAlertController를 만들어보겠다.

 

메세지를 빼오기 위해, 서버에서 넘어온 데이터를 decode 해야 한다.

GET 방식과 동일하게 decoder 선언해서 decode를 진행!

성공한 경우에도 메세지를 담아서 .success 반환하고

실패한 경우에도 메세지를 담아서 .requestErr를 반환한다.

 

UIViewController + makeAlert.swift


import Foundation
import UIKit

extension UIViewController
{
    func makeRequestAlert(title : String,
                   message : String,
                   okAction : ((UIAlertAction) -> Void)?,
                   cancelAction : ((UIAlertAction) -> Void)? = nil,
                   completion : (() -> Void)? = nil)
    {
        
        let generator = UIImpactFeedbackGenerator(style: .medium)
        generator.impactOccurred()
        
        let alertViewController = UIAlertController(title: title, message: message,
                                                    preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "확인", style: .default, handler: okAction)
        alertViewController.addAction(okAction)
        
        
        let cancelAction = UIAlertAction(title: "취소", style: .cancel, handler: cancelAction)
        alertViewController.addAction(cancelAction)
        

        self.present(alertViewController, animated: true, completion: completion)
    }
    
    
    func makeAlert(title : String,
                   message : String, 
                   okAction : ((UIAlertAction) -> Void)? = nil,
                   completion : (() -> Void)? = nil)
    {
        let generator = UIImpactFeedbackGenerator(style: .medium)
        generator.impactOccurred()
        
        let alertViewController = UIAlertController(title: title, message: message,
                                                    preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "확인", style: .default, handler: okAction)
        alertViewController.addAction(okAction)
        
        
        self.present(alertViewController, animated: true, completion: completion)
    }
}

 

LoginViewController.swift

import UIKit

class LoginViewController: UIViewController {

    @IBOutlet weak var idTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func loginButtonClicked(_ sender: Any) {
        
        self.makeRequestAlert(title: "알림",
                              message: "로그인을 하시겠습니까?",
                              okAction: { _ in
                                self.loginAction()
                              })
    }
    
    
    func loginAction()
    {
        LoginService.shared.login(email: self.idTextField.text!, password: self.passwordTextField.text!) { result in
            switch result
            {
            case .success(let message):
                
                if let message = message as? String{
                    
                    self.makeAlert(title: "알림",
                                   message: message)

                }
                
            case .requestErr(let message):
                
	                if let message = message as? String{
                    
                    self.makeAlert(title: "알림",
                              message: message)
                }
                           
                
            default :
                print("ERROR")
            }
        }
    }
    

}

코드 쪼개기 ..!

 1.
 self.makeRequestAlert(title: "알림",
                              message: "로그인을 하시겠습니까?",
                              okAction: { _ in
                                self.loginAction()

버튼이 눌리면, 아까 만들어둔 makeRequestAlert 를 통해 창을 띄운다.

"확인"을 눌렀을 때에는 실제 통신이 되어야 하기 때문에, okAction 클로저에다가

실제 로그인을 처리하는 부분인 loginAction() 을 넣었다.

2.
 LoginService.shared.login(email: self.idTextField.text!, password: self.passwordTextField.text!) { result in

1번에서 확인을 눌러서 loginAction 함수가 실행되었다면,

아까 만들어둔 LoginService 부분에서 shared를 통해서 싱글턴 인스턴스에 접근하게 되고,

각각 textField에 있는 text를 넘기게 된다.

통신의 결과값이 result로 반환!

3.   
case .success(let message):
                
                if let message = message as? String{
                    
                    self.makeAlert(title: "알림",
                                   message: message)

                }

성공적으로 result 값이 내려왔다면, 현재 여기 result 에는 message 값만 담겨 있다.

 

아까 LoginService에서 그렇게 message 부분만 빼서 전달했기 때문!

if - let 을 통해서 String 형으로 옵셔널 바인딩 후에, message 값을 가져왔다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함