반응형
Swift UI 를 사용한 회원가입 및 로그인 화면 구현 - 백엔드는 Django RestFramework 사용
구현 예시 - 회원가입
회원 가입은 4개 항목 (닉네임, 이메일, 비밀번호(+비밀번호 확인), MBTI 항목)을 입력받는 화면을 만든다. 여기서 MBTI 항목은 HTML에서 말하는 셀렉트 박스 UI를 사용하여 MBTI를 선택하도록 하였다.
//
// SignUpView.swift
// mbtiPlayground
//
// Created by 박종후 on 2022/03/16.
//
import SwiftUI
struct SignUpView: View {
@Environment(\\.presentationMode) var presentationMode: Binding<PresentationMode>
@State private var showingAlert = false
@State var uiTabarController: UITabBarController?
@State private var email: String = ""
@State private var password: String = ""
@State private var rePassword: String = ""
@State private var username: String = ""
@State private var mbti = 0
let mbtiPicker = ["ISTJ", "ISFJ", "INFJ", "INTJ", "ISTP", "ISFP", "INFP","INTP", "ESTP", "ESFP", "ENFP", "ENTP", "ESTJ", "ESFJ", "ENFJ", "ENTJ"]
var btnBack : some View { Button(action: {
self.showingAlert = true
}){
Text("뒤로가기")
}.alert(isPresented: $showingAlert){
Alert(title: Text("회원 가입 취소"), message: Text("회원가입을 취소하시겠습니까?"),
primaryButton: .destructive(Text("취소하기"), action: {
presentationMode.wrappedValue.dismiss()
})
, secondaryButton: .cancel(Text("이어하기")))
}
}
var body: some View {
VStack{
Text("Sign Up")
.font(.title)
.fontWeight(.medium)
.padding()
.foregroundColor(.black)
.frame(width: 300)
HStack{
Image(systemName: "tag")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.padding(.bottom)
TextField("닉네임을 입력하세요", text: $username)
.frame(width: 300, height: 10)
.padding()
.background(Color(.systemGray6))
.cornerRadius(5.0)
.padding(.bottom, 20)
}
HStack{
Image(systemName: "person.fill")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.padding(.bottom)
TextField("이메일을 입력하세요.", text: $email)
.frame(width: 300, height: 10)
.padding()
.background(Color(.systemGray6))
.cornerRadius(5.0)
.padding(.bottom, 20)
}
HStack{
Image(systemName: "lock")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.padding(.bottom)
SecureField("비밀번호를 입력하세요", text: $password)
.frame(width: 300, height: 10)
.padding()
.background(Color(.systemGray6))
.cornerRadius(5.0)
.padding(.bottom, 20)
}
HStack{
Image(systemName: "lock.rotation")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.padding(.bottom)
SecureField("비밀번호를 다시 입력하세요", text: $rePassword)
.frame(width: 300, height: 10)
.padding()
.background(Color(.systemGray6))
.cornerRadius(5.0)
.padding(.bottom, 20)
}
HStack{
Text("MBTI 유형을 선택하세요: ")
.font(.headline)
.fontWeight(.medium)
.padding()
Picker("MBTI 유형을 선택하세요", selection: $mbti){
ForEach(0 ..< mbtiPicker.count){
Text(self.mbtiPicker[$0])
}
}
}
Button(action: {
print(self.email + self.password + self.rePassword + String(self.mbtiPicker[self.mbti])+self.username)
sendPostRequest("<http://localhost:8000/auth/signup>", parameters:
["email": self.email, "username": self.username, "password": self.password, "mbti": self.mbtiPicker[self.mbti]]
){
responseObject, error in guard let _ = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
}
self.presentationMode.wrappedValue.dismiss()
}){
Text("회원가입")
.frame(width: 80, height: 10)
.font(.headline)
.foregroundColor(.white)
.padding()
.background(Color(.systemBlue))
.cornerRadius(10)
}
.padding()
.onSubmit {
}
}
.padding(.all, 30)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: btnBack)
}
}
struct SignUpView_Previews: PreviewProvider {
static var previews: some View {
SignUpView()
}
}
회원 가입 시 Post 요청으로 보내는 함수는 아래와 같다 sendPostRequest
import Foundation
func sendPostRequest(_ url: String, parameters: [String: String], completion: @escaping ([String: Any]?, Error?) -> Void) {
let targetUrl = URL(string: url)
let paramData = try? JSONSerialization.data(withJSONObject: parameters)
var request = URLRequest(url: targetUrl!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = paramData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let data = data, // is there data
let response = response as? HTTPURLResponse, // is there HTTP response
200 ..< 300 ~= response.statusCode, // is statusCode 2XX
error == nil // was there no error
else {
completion(nil, error)
return
}
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
completion(responseObject, nil)
}
task.resume()
}
그런데 위 함수를 보면 Pyhon 과는 다르게 Return 값이 없다.
이 코드에 대해 설명하자면 URLSession 안에 미리 요청 내용을 담아둔 후 호출, 실제 실행(task.resume()) 부분에서 호출하여 받은 내용을 가져온다.
그렇다보니 처음 swift 를 접한 나에게는 어떻게 API 응답 코드에 대해 처리하는지 의문이었다.
그래서 보통 사용은 아래처럼 사용하게 된다.
sendPostRequest("<http://localhost:8000/auth/signup>", parameters:
["email": self.email, "username": self.username, "password": self.password, "mbti": self.mbtiPicker[self.mbti]]
){
responseObject, error in guard let _ = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
}
self.presentationMode.wrappedValue.dismiss()
위 코드는 UI 코드 내에서 회원가입 버튼 클릭 시 액션에서 동작하는 함수이다. Swift 에서는 함수의 return 값을 클래스의 변수로 할당하는 부분이 있는 것이 아닌, 요청 함수 내에서 self.XXX 로 클래스 변수에 접근하여 값을 변경하는게 대부분이다.
이렇다보니 Swift UI 내에서 클래스 변수를 선언하고 잘 사용하는 방법을 연구하여야 한다.
반응형
'IOS(Swift)' 카테고리의 다른 글
[IOS/Swift] MBTI 카드 선택 게임 UI 구현 (0) | 2022.05.22 |
---|---|
[IOS/Swift] 콘텐츠 검색 앱 구현 - 4. 로그인 UI 구현 (0) | 2022.04.04 |
[IOS/Swift] 콘텐츠 검색 앱 구현 - 2. 채팅방 UI 구현 (0) | 2022.03.05 |
[IOS/Swift] 콘텐츠 검색 앱 구현 - 1. 콘텐츠 UI 구현 (0) | 2022.03.05 |