티스토리 뷰

1. Component 공부

(1) ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    let textField = UITextField()
    let button = UIButton(type: .system)
    let stepper = UIStepper()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Title"
//        navigationItem.title = "New Title"
        let image = UIImage(systemName: "face.smiling")
        let imageView = UIImageView(image: image)
        navigationItem.titleView = imageView
        
        view.addSubview(textField)
        view.addSubview(button)
        view.addSubview(stepper)
        
        textField.frame = CGRect(x: view.frame.midX - 100, y: view.frame.midY - 30, width: 200, height: 40)
        textField.layer.borderColor = UIColor.gray.cgColor
        textField.layer.borderWidth = 0.5
        textField.layer.cornerRadius = 4
        textField.delegate = self
        
        button.setTitle("Next", for: .normal)
        button.sizeToFit()
        let buttonWidth = button.frame.width
        button.frame.origin = CGPoint(x: view.frame.midX - buttonWidth / 2, y: view.frame.midY + 30)
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        
        let stpperWidth = stepper.frame.width
        stepper.frame.origin = CGPoint(x: view.frame.midX - stpperWidth / 2 , y: view.frame.midY - 100)
        stepper.addTarget(self, action: #selector(stepperChanged(_:)), for: .valueChanged)
    }
    
    @objc func buttonTapped(_ sender: UIButton) {
        let secondVC = SecondViewController()
        secondVC.label.text = textField.text ?? "🤢🤢🤢"
        present(secondVC, animated: true)
    }
    
    @objc func stepperChanged(_ sender: UIStepper) {
        
    }
}

extension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        print(textField.text)
        return true
        //return false -> 더 이상 입력이 되지 않음. (예를들어 글자수에 따라 더 이상 입력되지 않게 하기 위해서 사용할 수 있음)
    }
}

 TextField Delegate

  • delegate = self 를 잊지말 것
  • textField(_:shouldChangeCharactersIn:replacementString:) : 실시간으로 textField에 입력되는 text를 받아오는 delegate method. true를 리턴해야 작동함

 

(2) SecondViewController.swift

import UIKit

class SecondViewController: UIViewController {
    
    let label = UILabel()
    let backButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        view.addSubview(label)
        label.frame = CGRect(x: view.frame.midX - 100, y: view.frame.midY - 20, width: 200, height: 40)
        label.backgroundColor = .purple.withAlphaComponent(0.3)
        label.layer.borderWidth = 1
        label.layer.cornerRadius = 4
        label.textAlignment = .center
        
        view.addSubview(backButton)
        backButton.setTitle("Alert", for: .normal)
        backButton.sizeToFit()
        let buttonWidth = backButton.frame.width
        backButton.frame.origin = CGPoint(x: view.frame.midX - buttonWidth / 2, y: view.frame.midY + 30)
        backButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
    }
    
    @objc func buttonTapped(_ sender: UIButton) {
        let alert = UIAlertController(title: "🚨경고🚨", message: "마지막 창입니다.", preferredStyle: .alert)
        let cancelAction = UIAlertAction(title: "취소", style: .cancel)
        let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
            print(alert.textFields?.first?.text)
        }
        alert.addTextField()
//        alert.addTextField { textField in
//            textField.keyboardType = .numberPad
//        }
        alert.addAction(cancelAction)
        alert.addAction(confirmAction)
        present(alert, animated: true)
    }
}

① UIAlertController

  • alert에 textField를 넣어줄 때는 간단하게 alert.textField()만 해주면 됨. 여기서 클로저도 추가 가능 (주석 참고)

2. (지난 주에 이어) Ratings project

(1) AddPlayerViewController.swift

import UIKit

class AddPlayerViewController: UIViewController {

    
//     let들은 순서가 보장되지 않음
//     보장하기 위해 lazy var를 사용
//     let layout = UICollectionViewLayout()
//    lazy var collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
    
    
    let tableView = UITableView(frame: .zero, style: .grouped)
    
    lazy var cancelBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(barButtonItemTapped(_:)))
    lazy var doneBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(barButtonItemTapped(_:)))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(tableView)
        tableView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
        tableView.dataSource = self
        title = "Add Player"
        
        tableView.register(AddPlayerTextFieldTableViewCell.self, forCellReuseIdentifier: AddPlayerTextFieldTableViewCell.identifier)
        
        navigationItem.leftBarButtonItem = cancelBarButtonItem
        navigationItem.rightBarButtonItem = doneBarButtonItem
    }
    
    @objc func barButtonItemTapped(_ sender: UIBarButtonItem) {
        // lazy var를 이용해야 함
        // 함수가 불릴 때 버튼은 생성되지 않음
        switch sender {
        case cancelBarButtonItem:
            print("cancle")
        case doneBarButtonItem:
            print("don")
        default:
            break
        }
    }
}

extension AddPlayerViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if section == 0 {
            return "PLAYER NAME"
        }
        return nil
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: AddPlayerTextFieldTableViewCell.identifier, for: indexPath) as? AddPlayerTextFieldTableViewCell else { fatalError() }
        if indexPath.section == 0 {
            return cell
        } else {
            let basicCell = UITableViewCell()
            basicCell.textLabel?.text = "Game"
            basicCell.accessoryType = .disclosureIndicator
            let label = UILabel.init(frame: CGRect(x:0,y:0,width:100,height:20))
            label.text = "Detail"
            basicCell.accessoryView = label
            return basicCell
        }
    }
}

① cancelBarButtonItem과 doneBarButtonItem을 lazy var로 선언하지 않으면 버튼 액션(barButtomItemTapped)에서 sender가 nil값이 됨.

  • let으로 선언했던 BarButtonItem들이 함수(barButtomItemTapped)보다 생성되기 때문임.
  • 해당 변수들(cancelBarButtonItem, doneBarButtonItem)을 lazy로 선언해주면 실행 순서가 보장되기 때문에 원하는대로 sender 값이 들어옴
  • collectionView를 만들 때도 마찬가지임. layout 상수가 collectionView를 초기화할 때 필요한 요소인데, 생성 순서가 보장되지 않기 때문에 collectionView를 지연저장 속성으로 만들어서 생성 순서를 보장하면 됨
class ViewController: UIViewController {

    let layout = UICollectionViewLayout()
    lazy var collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
    
    override func viewDidLoad() {
    	super.viewDidLoad()
    }
}

 

(2) AddPlayerTextFieldTableViewCell.swift

import UIKit

class AddPlayerTextFieldTableViewCell: UITableViewCell {
    
    static let identifier = "AddPlayerTextFieldTableViewCell"
    
    let textField = UITextField()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.addSubview(textField)
        
        textField.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
}

<오늘의 배운 점>

1. UIAlertContoroller에 textField 추가하는 방법과 handler 사용

2. frame으로 UI짜기 (중심 잡기)

3. lazy var의 실제 사용

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크