개발 못해요! 그냥 못해요
[iOS/Swift] 프로젝트 생성 | 화면 전환 | 데이터 전달 (당근 클론 코딩) 본문
프로젝트 생성하기
폰트 사용하기
font 폴더를 만들어준당
원하는 폰트를 다운 받아 만들어준 폴더에 넣어준다(pretedard를 사용했다)
info.plist에서 Fonts proided by application을 추가로 생성해주고 아이템을 추가한다
{폰트명.확장자}까지 작성해준다
폰트 설정 끝~~
UIComponent (Login 화면 만들기)
LoginViewController 생성
- UIKit 임포트하기
import Foundation
import UIKit
class LoginViewController: UIViewController{
}
//
// LoginViewController.swift
// 34th-Sopt-Seminar
//
// Created by 김민서 on 2024/03/31.
//
import Foundation
import UIKit
class LoginViewController: UIViewController{
//UILabel
//타이틀 텍스트
private let titleLabel: UILabel = {
let label = UILabel (frame: CGRect(x:69,y:161,width:236,height:44))
label.text = "동네라서 가능한 모든 것\n 당근에서 가까운 이웃과 함께해요."
label.textColor = .black
label.textAlignment = .center
label.numberOfLines = 2
label.font = UIFont(name:"Pretendard-Bold",size: 18)
return label
}()
//아이디 입력창
private let idTextField: UITextField = {
let textField = UITextField(frame: CGRect(x: 20, y: 276, width: 335, height: 52))
textField.placeholder = "아이디"
textField.font = UIFont(name:"Pretendard-Medium",size:14)
textField.backgroundColor = UIColor(red: 221/255, green: 222/255, blue: 227/255, alpha: 1)
textField.layer.cornerRadius = 3
//padding
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 23, height: textField.frame.height))
textField.leftView = paddingView
textField.leftViewMode = .always
return textField
}()
//비밀번호 입력창
private let passwordTextField: UITextField = {
let textField = UITextField(frame: CGRect(x: 20, y: 335, width: 335, height: 52))
textField.placeholder = "비밀번호"
textField.font = UIFont(name:"Pretendard-Medium",size:14)
textField.backgroundColor = UIColor(red: 221/255, green: 222/255, blue: 227/255, alpha: 1)
textField.layer.cornerRadius = 3
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 23, height: textField.frame.height))
textField.leftView = paddingView
textField.leftViewMode = .always
return textField
}()
//로그인 버튼
private lazy var loginButton: UIButton = {
let button = UIButton(frame: CGRect(x: 21, y: 422, width: 332, height: 58))
button.backgroundColor = UIColor(red: 255/255, green: 111/255, blue: 15/255, alpha: 1)
button.setTitle("로그인하기", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont(name:"Pretendard-Bold",size:18)
button.layer.cornerRadius = 6
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
[titleLabel,idTextField,passwordTextField,loginButton].forEach{
self.view.addSubview($0)
}
}
}
imageView (WelcomeViewController)
assets 폴더를 생성해 사용할 이미지 파일을 넣어준다
private let imageView : UIImageView = {
let imageView = UIImageView(frame: CGRect(x: 112, y: 87, width: 150, height: 150))
imageView.image = UIImage(named:"puppy.png")
return imageView
}()
다른 컴포넌트와 마찬가지로 크기, 위치를 지정하고
imageView.image = UIImage(named:"파일명")으로 이미지를 불러온다~
다른 요소들도 앞에서 작성한것처럼 컴포넌트를 생성해준다
//
// WelcomeViewController.swift
// 34th-Sopt-Seminar
//
// Created by 김민서 on 2024/03/31.
//
import Foundation
import UIKit
class WelcomeViewController:UIViewController{
var id:String?
private let imageView : UIImageView = {
let imageView = UIImageView(frame: CGRect(x: 112, y: 87, width: 150, height: 150))
imageView.image = UIImage(named:"puppy.png")
return imageView
}()
private let welcomeLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 140, y: 295, width: 95, height: 60))
label.text = "???님\n반가워요!"
label.textColor = .black
label.textAlignment = .center
label.numberOfLines = 2
label.font = UIFont(name:"Pretendard-ExtraBold",size:25)
return label
}()
private lazy var mainButton: UIButton = {
let button = UIButton(frame: CGRect(x: 20, y: 426, width: 335, height: 58))
button.backgroundColor = UIColor(red: 255/255, green: 111/255, blue: 15/255, alpha: 1)
button.setTitle("메인으로", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont(name:"Pretendard-Bold",size:18)
button.layer.cornerRadius = 6
return button
}()
private lazy var backTologinButton: UIButton = {
let button = UIButton(frame: CGRect(x: 20, y: 498, width: 335, height: 58))
button.backgroundColor = UIColor(red: 221/255, green: 222/255, blue: 227/255, alpha: 1)
button.setTitle("다시 로그인", for: .normal)
button.setTitleColor(UIColor(red: 172/255, green: 176/255, blue: 185/255, alpha: 1), for: .normal)
button.layer.cornerRadius = 6
button.titleLabel?.font = UIFont(name:"Pretendard-Bold",size:18)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
[imageView,welcomeLabel,mainButton,backTologinButton].forEach{
self.view.addSubview($0)
}
}
}
화면 전환(1)
두 개의 화면을 만들었으니 이제 화면을 전환할 수 있도록 연결해보자!
1️⃣ presentToWelcomeVC()
: 모달 방식으로 화면 띄우기
private func presentToWelcomeVC(){
let welcomeViewController = WelcomeViewController()
welcomeViewController.modalPresentationStyle = .formSheet
self.present(welcomeViewController, animated: true)
}
- 이동할 뷰 컨트롤러를 선언해준다
- modalPresentationStyle 속성으로 어떻게 모달 띄울지 설정 (여러가지 방식이 있다)
- present 함수를 사용해 모달 방식으로 화면을 전환해준다
2️⃣ pushToWelcomeVC()
: 네비게이션 방식으로 화면 띄우기
private func pushToWelcomeVC(){
let welcomeViewController = WelcomeViewController()
self.navigationController?
.pushViewController(welcomeViewController, animated:true)
}
- 이동할 뷰 컨트롤러를 선언해준다
- navigationcontroller로 push를 진행해준다
버튼을 눌렀을 때 위에서 만든 함수를 호출할 수 있도록 코드 작성하기
@objc
private func loginButtonDidTap() {
presentToWelcomeVC()
//pushToWelcomeVC()
}
로그인 버튼을 눌렀을 때 앞에서 선언한 함수 중 어떤 방식을 실행할지 선언하기
private lazy var loginButton: UIButton = {
let button = UIButton(frame: CGRect(x: 21, y: 422, width: 332, height: 58))
button.backgroundColor = UIColor(red: 255/255, green: 111/255, blue: 15/255, alpha: 1)
button.setTitle("로그인하기", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont(name:"Pretendard-Bold",size:18)
button.layer.cornerRadius = 6
//버튼 이벤트
button.addTarget(self, action: #selector(loginButtonDidTap), for: .touchUpInside)
return button
}()
❗️@objc
Swift를 사용한 코드를 Objective-C 코드와 상호작용 시키기 위해 사용
❗️#selcetor
함수를 직접 지정해서 실행할 때 사용
❗️addTarget
controlEvent가 수행되었을 때 실행 주체인 Target과 함수를 연결해주는 함수
화면 전환(1)
뒤로 가는 화면도 비슷하게 작성해주면 된다~
welcomeViewController에서 작성하기
//이전 화면으로 가기
@objc
private func backToLoginButtonDidTap(){
//nav controller 사용시 dismiss 방식
if self.navigationController == nil {
self.dismiss(animated: true)
} else {//그게 아닐 시 pop 방식
self.navigationController?.popViewController(animated: true)
}
}
만약 네비게이션 방식으로 이동하지 않았다면 dismiss
네비게이션 방식으로 이동하면 popViewController
데이터 전달하기
1️⃣ 입력받을 전역변수 선언 및 데이터 바인딩 함수 구현
var id: String = " "
아이디를 입력받을 전역 변수 선언
2️⃣ 화면의 라벨과 받아온 변수를 연결해주는 bindID 함수 선언
private func bindID() {
self.welcomeLabel.text = "\(id)님 \n반가워요!"
}
해당 함수를 ViewDidLoad에서 호출
welcomeViewController.id = idTextField.text
LoginVC로 넘어와서 화면 전환을 하기 위한 다음 뷰컨의 객체를 만드는 부분에 접근해, 해당 변수의 값을 바꿔준다
🚨근데? 에러가 발생
스위프트에서 변수를 선언할때 non-optional 값을 줘야함
즉, 어떤 값을 변수에 줘야하지만 지금 처럼 nil 값을 주고 싶다면
Optional 타입을 사용하기!
타입명 + ?
- 값이 할당 되었을 때 그 값을 그대로 가짐
- 옵셔널 변수에 값을 할당되지 않았을 때 nil 가짐
근데? 또 문제 발생 옵셔널 사용시 Optional(" ")형태로 출력이 되어 안에 있는 내용만 꺼내야함!!
옵셔널 바인딩
1️⃣ if let
: nil / nil이 아닐 때 두가지로 나눠서 분기처리 가능
2️⃣ guard let
: nil이 아닐 때만 유의미한 코드 진행 / nil일 경우 끝 혹은 에러 문구 만 가능
//데이터 바인딩 함수 구현
private func bindID(){
guard let idText = id else { return }
self.welcomeLabel.text="\(idText)님 \n반가워요!"
}
guard let 형식으로 작성
- nil 일때 return
- nil이 아닐 때 넘겨 받은 id 값 사용
프로퍼티와 함수 이용
함수를 이용해 private하게 선언된 변수들을 바꾸어 주기
1️⃣ setLabelText 함수 만들기
선언했던 전역 변수 id에 함수를 통해 값을 바꾸어 주고 ViewdidLoad 함수 안 bindText() 함수가 실행되게 만드는 과정을 통해 텍스트로 바꾸어 줌
private func setLabelText(id: String?) {
self.id = id
}
2️⃣ LoginViewController에서 해당 함수 값을 넣어주기
id 프로퍼티를 전역변수가 아닌 private하게 선언된 변수로 바꿀 수 있음
//welcomeViewController.id = idTextField.text
welcomeViewController.setLabelText(id: idTextField.text)
💡생각해보기💡
✅ final 키워드를 왜 사용할까요? 성능적 이점에는 무엇이 있을까요?
✅ 접근제어자가 무엇인지 설명하고, 왜 사용해야 될까요?
: 접근 제어는 코드 간 상호 작용 시 파일 혹은 모듈간 접근을 제어할 수 있는 기능
왜 써야하나?
1. 외부로부터 데이터를 보호하기 위해서
2. 외부에는 불필요하고 내부적으로만 사용되는 부분을 감추기 위해서
접근 수준 키워드를 통해 구현하고 open / public / internal / fileprivate / private 가 있음
open (개방 접근 수준)
- 클래스와 클래스의 멤버에서만 사용할 수 있음
- 해당 멤버가 정의된 모듈 밖의 다른 모듈에서도 재정의 할 수 있음
public (공개 접근 수준)
- 어디서든 사용할 수 있음
internal (내부 접근 수준)
- 소스파일이 속해 있는 모듈 어디에서든 쓰일 수 있음
- 그 모듈을 가져다 쓰는 외부 모듈에서는 접근 불가
- 기본 접근 수준으로 굳이 표기 하지 않아도 됨
fileprivate (파일 외부 비공개 접근 수준)
- 요소가 구현된 소스 파일 내부에서만 사용할 수 있음
- 소스파일 외부에서 값이 변경되거나 함수를 호출하면 부작용이 생길 수 있는 경우에 사용하면 좋음
private (비공개 접근 수준)
- 가장 한정적인 범위
- 기능을 정의하고 구현한 범위 내에서만 사용할 수 있음
- 같은 소스파일 안에 구현한 다른 타입이나 기능에서도 사용할 수 없음
그 중에서도 과제에서 쓰인 private을 예시로 말해보겠음!
비공개 접근 수준은 가장 한정적이고 지정된 요소는 그 기능을 정의하고 구현한 범위 내에서만 사용 가능
private var id: String?
private으로 변수 id를 선언해주어서 WelcomeViewController 클래스 외부에서는 접근이 불가능하게 해줌
func setLabelText(id: String?) {
self.id = id
}
그래서 id 값을 외부에서 설정 할 수 있도록 setLabelText(id:)함수를 선언해줌
private func presentToWelcomeVC(){
let welcomeViewController = WelcomeViewController()
welcomeViewController.modalPresentationStyle = .formSheet
welcomeViewController.setLabelText(id: idTextField.text)
//welcomeViewController.id = idTextField.text
self.present(welcomeViewController, animated: true)
}
id는 private으로 선언되어 LoginViewController에서 직접적으로 접근 불가하기 때문에 presentToWelcome 메서드에서 WelcomeViewController 인스턴스의 setLabelText(id:) 메서드를 호출해 id 값을 해당 메서드로 전달해줌 !!
사실 이거 이해하는 것도 너무나도 오래 걸려서 나머지 키워드들도 차차 정리해볼게요 ㅜㅜ
✅ lazy var, let으로 프로퍼티를 선언하였는데 둘의 차이점은 무엇일까요? 만약 해당 코드가 없다면 어떻게 될까요
✅ 생명주기는 정말 중요합니다! 다시 한번 꼭꼭 정리해주세요!
'Study > iOS' 카테고리의 다른 글
[swift] 타입/기본 연산자/ 조건문/ 반복문 (1) | 2024.05.03 |
---|