아 -> 위 (Modal) : present - dismiss
// 이전 화면. nextButtonTapped()
present(vc, animated: true, completion: nil)
// 다음 화면. closeButtonTapped()
dismiss(animated: true, completion: nil)
오 -> 외 (Show) : push - pop
// 이전 화면. nextButtonTapped()
navigationController?.pushViewController(vc, animated: true)
// 다음 화면. closeButtonTapped()
navigationController?.popViewController(animated: true)
A -> B 데이터 전송
var contents: String?
vc.contents = list[indexPath.row]
mainLabel.text = contents
** mainLabel.text = list[indexPath.row]
cell.contentLabel.numberOfLines = 0
tableView.rowHeight = UITableView.automaticDimension
편집 상태로 바꿔준다
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
편집한다
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
list.remove(at: indexPath.row)
tableView.reloadData()
}
let nib = UINib(nibName: "TestCollectionViewCell", bundle: nil)
mainTableView.register(nib, forCellWithReuseIdentifier: "TestCollectionViewCell")
// 1
class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // 1
// 3
@IBOutlet var mainTableView: UITableVIew!
override func viewDidLoad() {
super.viewDidLoad()
// 2
mainTableView.delegate = self
mainTableView.dataSource = self
}
}
cellForRowAt
numberOfRowsInSection
enum + 연산 프로퍼티 조합이 아주 깡패다
enum SettingOptions: Int, CaseIterable {
case total, personal, others // 그냥 케이스
// enum에서 타입 프로퍼티는 사용 가능!!
// rawValue는 Int이지만, 타입 프로퍼티로 String을 받아올 수 있다!!
var mainOptions: String { // (섹션 이름)
// get만 쓸 때는 생략 가능
//get {
switch self {
case .total : return "전체"
case .personal : return "개인"
case .others : return "기타"
}
//}
}
var subOptions: [String] { // (셀 이름)
switch self {
case .total : return ["공지사항", "실험실", "버전 정보"]
case .personal : return ["노트북", "핸드폰", "충전기", "케이블"]
case .others : return ["애플", "삼성"]
}
}
}
실제 코드에 적용
// 1. 섹션 개수
return SettingOptions.allCases.count
// 2. 섹션 텍스트
return SettingOptions.allCases[section].mainOptions
// 3. 셀 개수
return SettingOptions.allCases[section].subOptions.count
// 4. 셀 텍스트
cell.textLabel?.text = SettingOptions.allCases[indexPath.section].subOptions[indexPath.row]
awakeFromNib()
내에 정적인 데이터를 선언한다override func awakeFromNib() {
super.awakeFromNib()
mainTitleLabel.font = .boldSystemFond(ofSize: 17)
mainTitleLabel.textColor = .brown
}
// 프로토콜 채택
class DetailViewController: UIViewController, UITextViewDelegate {
// placeholder로 사용할 텍스트
var placeholderText = "내용을 입력해주세요"
// outlet 연결
@IBOutlet var contentTextView: UITextView!
// 초기 설정
override func viewDidLoad() {
contentTextView.delegate = self
if contentTextView.text.isEmpty {
contentTextView.text = placeholderText
contentTextView.textColor = .lightgray
}
}
// 커서가 깜빡깜빡
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.text == placeholderText {
textView.text = ""
textView.textColor = .blace
}
}
// 커서 없어짐
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = placeholderText
textView.textColor = .red
}
}
// 프로토콜 채택
class LottoViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
// 버튼인 척 할 textfield 아웃렛
@IBOutlet var numberTextField: UITextField!
// pickerView는 스토리보드에 얹는 게 아니고,
// 빈 상태로 코드에서 만들어준다
let pickerView = UIPickerView()
// pickerView에 뜨게 할 요소들
var list: [Int] = Array(1...1000).reversed()
override func viewDidLoad() {
super.viewDidLoad()
// 키보드가 떠야 하는 inputView를 바꿔버려
numberTextField.inputView = pickerView
// 커서도 안보이게 clear 색깔로 해버리자
numberTextField.tintColor = .clear
// 프로토콜 연결
pickerView.delegate = self
pickerView.dataSource = self
}
// 함수 4개 선언
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return list.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
numberTextField.text = "\(list[row])"
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return "\(list[row])"
}
}
Onboarding Screen
// 할 일 : 1. login 상태 2. 화면 전환
@IBAction func loginButtonTapped(_ sender: UIButton) {
// login되었다고 상태 저장
UserDefaults.standard.set(true, forKey: "isLogin")
print("UserDefault 변경. true")
// 다음 화면 넘어감
// 1 + 2. 같은 스토리보드
let vc = storyboard?.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
// 3. 화면 전환 방식
vc.modalPresentationStyle = .fullScreen
// 4. 화면 띄우기
present(vc, animated: true)
}
Main Screen
// 할 일 : 1. 화면 전환
@IBAction func settingButtonTapped(_ sender: UIButton) {
// 화면 이동
// 1 + 2. 같은 스토리보드
let vc = storyboard?.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
// 3. 화면 전환 방식
vc.modalPresentationStyle = .fullScreen
// 4. 화면 띄우기
present(vc, animated: true)
}
Setting Screen
// 할 일 : 1. logout 상태 2. rootview 수정
@IBAction func logoutButtonTapped(_ sender: UIButton) {
// 1. userdefault 수정
UserDefaults.standard.set(false, forKey: "isLogin")
print("UserDefault 변경. false")
// 2. 루트 뷰까지 초기화
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
let sceneDelegate = windowScene?.delegate as? SceneDelegate
let vc = storyboard?.instantiateViewController(identifier: "OnboardingViewController") as! OnboardingViewController
sceneDelegate?.window?.rootViewController = vc
sceneDelegate?.window?.makeKeyAndVisible()
}
print(#function)
을 넣어서 로그가 찍히게 했다로그인o
// 온보딩 화면
UserDefaults : false
onboarding viewDidLoad()
onboarding viewWillAppear(_:)
onboarding viewDidAppear(_:)
// 로그인 버튼 클릭 -> 메인화면
UserDefault 변경. true
main viewDidLoad()
onboarding viewWillDisappear(_:)
main viewWillAppear(_:)
main viewDidAppear(_:)
onboarding viewDidDisappear(_:)
// 설정 버튼 클릭 -> 설정화면
setting viewDidLoad()
main viewWillDisappear(_:)
setting viewWillAppear(_:)
setting viewDidAppear(_:)
main viewDidDisappear(_:)
/* 여기까지는 일반적인 화면 전환 시 생명주기 함수의 실행과 동일*/
// 로그아웃 버튼 클릭 -> 온보딩 화면
UserDefault 변경. false
setting viewWillDisappear(_:)
main viewWillAppear(_:)
main viewDidAppear(_:)
setting viewDidDisappear(_:)
main viewWillDisappear(_:)
onboarding viewWillAppear(_:)
onboarding viewDidAppear(_:)
main viewDidDisappear(_:)
onboarding viewWillDisappear(_:)
onboarding viewDidLoad()
onboarding viewWillAppear(_:)
onboarding viewDidDisappear(_:)
onboarding viewDidAppear(_:)
/* 초기화면도 onboarding이었기 때문에 두 onboarding이 겹친다 */
로그인x
// 메인 화면
UserDefaults : true
main viewDidLoad()
main viewWillAppear(_:)
main viewDidAppear(_:)
// 설정 버튼 클릭 -> 설정 화면
setting viewDidLoad()
main viewWillDisappear(_:)
setting viewWillAppear(_:)
setting viewDidAppear(_:)
main viewDidDisappear(_:)
/* 여기까지는 일반적인 화면 전환 시 생명주기 함수의 실행과 동일*/
// 로그아웃 버튼 클릭 -> 온보딩 화면
UserDefault 변경. false
setting viewWillDisappear(_:)
main viewWillAppear(_:)
main viewDidAppear(_:)
setting viewDidDisappear(_:)
main viewWillDisappear(_:)
onboarding viewDidLoad()
onboarding viewWillAppear(_:)
main viewDidDisappear(_:)
onboarding viewDidAppear(_:)
로그아웃 버튼을 누르면, 이제껏 쌓여있던 화면들이 역순으로 순식간에 전환이 일어나는 걸 확인할 수 있다.
감사합니다. 이런 정보를 나눠주셔서 좋아요.