아삭아삭 iOS 개발

[TIL] 2022.07.12 (SeSAC iOS) 본문

TIL(Today I Learned)

[TIL] 2022.07.12 (SeSAC iOS)

바닐라머스크 2022. 7. 12. 23:42

 

오늘 공부한 내용들을 내가 잊지 않기 위해 기록합니다.

틀린 내용이 있을 수 있는 점 참고 부탁드립니다 :)

 

■ 오늘의 과제

1) Raw String

과제목표 : swift5에서 새로 등장한 rawstring이 무엇인지 알아보고, playground에서 실습해보기 (스스로 학습 및 구현)

 

(정리한 내용과 예시들은 playground로 구현해보며 내용이 길어져 별도 포스팅으로 업로드 예정입니다~)

//링크 예정 자리//

 

 


2) 감정 다이어리 프로젝트 코드 개선

과제목표 : 함수의 반환값, 열거형, 등을 활용해 감정 다이어리 프로젝트 코드 개선수정

 

 

■ 개선사항

<AS-IS> <TO-BE>
감정버튼 9개 개별 Outlet 연결 감정버튼 9개 모두 하나의 Outlet Collection 연결
스토리보드를 통한 감정버튼 Image 9개 개별등록 코드상 반복문(for문)을 통한 감정버튼 Image 9개 일괄등록
감정별 클릭 수가 담길 변수 9개 개별생성 감정별 클릭 수가 담길 배열 1개 통합생성
switch문을 사용한 감정일기 로직 구현
- 각 감정 9개에 해당할 경우, 클릭 수 개별증가
- 그 외
tag를 사용한 감정일기 로직 구현
- 클릭된 버튼의 tag에 해당하는 감정숫자 증가 및 출력
감정 레이블에서 String 출력 감정 레이블에서 Raw String 사용
(필요기능은 아니나 오늘 공부내용 활용 목적)

 

■ 추가 공부 필요 Keyword

  • tag를 사용한 추가적인 케이스 및 샘플

 

■ 상세코드

<AS-IS>

import UIKit

class ViewController: UIViewController {

    var emotionDataArray: [Emotion] = [
        Emotion(emotionalSlime: UIImage(named: "sesac_slime1.png")!, emotions: "행복해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime2.png")!, emotions: "사랑해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime3.png")!, emotions: "좋아해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime4.png")!, emotions: "분노해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime5.png")!, emotions: "심심해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime6.png")!, emotions: "지루해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime7.png")!, emotions: "당황해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime8.png")!, emotions: "서운해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime9.png")!, emotions: "슬퍼해")
    ]
    
    @IBOutlet weak var slime1: UIButton!
    @IBOutlet weak var slime2: UIButton!
    @IBOutlet weak var slime3: UIButton!
    @IBOutlet weak var slime4: UIButton!
    @IBOutlet weak var slime5: UIButton!
    @IBOutlet weak var slime6: UIButton!
    @IBOutlet weak var slime7: UIButton!
    @IBOutlet weak var slime8: UIButton!
    @IBOutlet weak var slime9: UIButton!

    @IBOutlet var emotionLabels: [UILabel]!
    
    var n1: Int = 0
    var n2: Int = 0
    var n3: Int = 0
    var n4: Int = 0
    var n5: Int = 0
    var n6: Int = 0
    var n7: Int = 0
    var n8: Int = 0
    var n9: Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
    }
    
    // MARK: - 초기화면 ui설정
    func setUI() {
        for i in 0...8 {
//            emotionButtons[i].setImage(emotionDataArray[i].emotionalSlime, for: .normal)
            emotionLabels[i].text = "\(emotionDataArray[i].emotions) 0"
        }
    }
    
    // MARK: - 감정버튼 클릭시 로직
    @IBAction func buttonTapped(_ sender: UIButton) {
        
        switch sender {
        case slime1:
            n1 += 1
            emotionLabels[0].text = "\(emotionDataArray[0].emotions) \(n1)"
            
        case slime2:
            n2 += 1
            emotionLabels[1].text = "\(emotionDataArray[1].emotions) \(n2)"
            
        case slime3:
            n3 += 1
            emotionLabels[2].text = "\(emotionDataArray[2].emotions) \(n3)"
            
        case slime4:
            n4 += 1
            emotionLabels[3].text = "\(emotionDataArray[3].emotions) \(n4)"
            
        case slime5:
            n5 += 1
            emotionLabels[4].text = "\(emotionDataArray[4].emotions) \(n5)"
            
        case slime6:
            n6 += 1
            emotionLabels[5].text = "\(emotionDataArray[5].emotions) \(n6)"
            
        case slime7:
            n7 += 1
            emotionLabels[6].text = "\(emotionDataArray[6].emotions) \(n7)"
            
        case slime8:
            n8 += 1
            emotionLabels[7].text = "\(emotionDataArray[7].emotions) \(n8)"
            
        case slime9:
            n9 += 1
            emotionLabels[8].text = "\(emotionDataArray[8].emotions) \(n9)"
            
        default:
            print("오늘은 별 감정이 들지 않았습니다.")
        }
    }
}

 

<TO-BE>

import UIKit

struct Emotion {
    var emotionalSlime: UIImage
    let emotions: String
}
import UIKit

class ViewController: UIViewController {
    
    var emotionDataArray: [Emotion] = [
        Emotion(emotionalSlime: UIImage(named: "sesac_slime1.png")!, emotions: "행복해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime2.png")!, emotions: "사랑해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime3.png")!, emotions: "좋아해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime4.png")!, emotions: "분노해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime5.png")!, emotions: "심심해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime6.png")!, emotions: "지루해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime7.png")!, emotions: "당황해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime8.png")!, emotions: "서운해"),
        Emotion(emotionalSlime: UIImage(named: "sesac_slime9.png")!, emotions: "슬퍼해")
    ]
    
    @IBOutlet var slimeImages: [UIButton]!
    @IBOutlet var emotionLabels: [UILabel]!
    
    var emotionArray = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        for i in 0...8 {
            slimeImages[i].setImage(emotionDataArray[i].emotionalSlime, for: .normal)
            emotionLabels[i].text = #"\#(emotionDataArray[i].emotions) "0""#
        }
    }
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        emotionArray[sender.tag] += 1 // 클릭한 버튼의 tag 찾고, 해당 서브스크립트 감정숫자에 1 더해줌
        emotionLabels[sender.tag].text = #"\#(emotionDataArray[sender.tag].emotions) \#(emotionArray[sender.tag])"# // 전체 감정숫자 출력
    }
}

 

 


3) 신조어 검색기 프로젝트 코드 개선

과제목표 : 함수의 반환값, 열거형, 스위치 구문 등을 활용해 신조어 검색기 프로젝트 코드 개선수정

 

■ 개선사항

<AS-IS> <TO-BE>
신조어 데이터 dictionary로 정의 신조어 데이터 enum로 정의
해시테그 샘플용으로 dictionary의 key값 4개 랜덤추출 해시테그 샘플용으로 enum의 allCases에서 4개 랜덤추출
if구문을 사용한 신조어 검색결과 추출 로직 구현
- 공란으로 검색할 경우
- dictionary의 key값과 일치하지 않는 경우
-  dictionary의 key값과 일치한 경우
switch구문을 사용한 신조어 검색결과 추출 로직 구현
- 각 신조어 rawValue에 해당하는 경우
- 그 외

 

■ 추가 공부 필요 Keyword

  • CustomStringConvertible 프로토콜
  • CaseIterable 프로토콜
  • enum, switch 구문 활용 예시 등

 

■ 상세코드

<AS-IS>

import UIKit

class HomeViewController: UIViewController, UITextFieldDelegate {
    
    var newCoinedWord: [String : String] = [
        "윰차" : "유명인과 무명인을 차별한다는 뜻",
        "알잘딱깔쎈" : "알아서 잘! 깔끔하고 센스있게~!",
        "내또출" : "내일 또 출근한다",
        "H워얼V" : "사랑한다는 뜻. 사랑해의 형태를 뒤집어서 표현한 것",
        "많관부" : "'많은 관심 부탁드립니다'의 줄임말",
        "회의주의자" : "뻑하면 회의하자고 하는 직장인",
        "글설리" : "글쓴이를 설레게 하는 리플",
        "Whyrano" : "왜이러냐의 사투리 표현인 와이라노를 영어로 적은 말",
        "너 뭐 돼?" : "'너가 혹시 뭐라도 돼? 라는 뜻으로 유튜버 레오제이님으로 유명해진 유행어",
        "당모치" : "당연히 모든 치킨은 옳다",
        "돼지런하다" : "평소에는 행동이 느린데 먹을 때만 엄청 부지런하다",
        "무물" : "무엇이든 물어보세요"
    ]

    @IBOutlet weak var searchTextField: UITextField!
    @IBOutlet var hashTags: [UIButton]!
    @IBOutlet weak var resultLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        changeNewCoinedWordRandom()
        setUI()
        searchTextField.delegate = self
    }
    
    func setUI() {
        // 검색 텍스트 필드 설정
        searchTextField.keyboardType = .default
        searchTextField.backgroundColor = UIColor.white
        searchTextField.borderStyle = .line
        searchTextField.layer.borderColor = UIColor.black.cgColor
        searchTextField.attributedPlaceholder = NSAttributedString(string: "신조어를 입력해주세요!", attributes: [NSAttributedString.Key.foregroundColor : UIColor.lightGray])
        searchTextField.autocorrectionType = .no
        // 텍스트필드 내부에 좌측 여백주기
        searchTextField.leftPadding()
        
        // hashTags ui 설정
        for i in hashTags {
            i.backgroundColor = .white
            i.layer.borderWidth = 1
            i.layer.borderColor = UIColor.black.cgColor
            i.setTitleColor(.black, for: .normal)
        }
        
        // 결과라벨
        resultLabel.textColor = .black
        resultLabel.font = UIFont.systemFont(ofSize: 18)
        resultLabel.text = "신조어의 의미를 알아봅시다!"
    }
    
    // MARK: - 신조어 예제 해쉬테그 랜덤표기
    func changeNewCoinedWordRandom() {
        // 신조어 키값 4개를 랜덤으로 추출하기
        var randomKeys: [String] = []
        
        while randomKeys.count < 4 {
            let randomkey = newCoinedWord.keys.randomElement()!
            
             if !randomKeys.contains(randomkey) {
                 randomKeys.append(randomkey)
             }
             print(randomKeys.sorted())
        }
    
        // 버튼 4개에 반복하여 적용
        for i in 0...3 {
            hashTags[i].setTitle("\(randomKeys[i])", for: .normal)
            hashTags[i].setTitleColor(.black, for: .normal)
            hashTags[i].backgroundColor = .white
            hashTags[i].layer.cornerRadius = 8
            hashTags[i].clipsToBounds = true
            hashTags[i].layer.borderWidth = 1
            hashTags[i].layer.borderColor = UIColor.black.cgColor
        }
    }
    
    // MARK: - 검색버튼 클릭시
    @IBAction func searchButtonTapped(_ sender: UIButton) {
        searchLogic()
        changeNewCoinedWordRandom()
    }
    
    // MARK: - 키보드 엔터키 클릭시
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        searchLogic()
        changeNewCoinedWordRandom()
        return true
    }
    
    // MARK: - 신조어 검색 로직 및 키보드 내리기
    func searchLogic() {
        
        // searchTextField.text? == "" 대신 .isEmpty로 개선
        if searchTextField.text!.isEmpty {
            self.presentAlert(title: "신조어를 입력해주세요.")
            return
        } else if !newCoinedWord.keys.contains(searchTextField.text!) {
            self.presentAlert(title: "찾으시는 신조어가 사전에 없습니다. 다른 신조어를 검색해주세요.")
            return
        }
        resultLabel.text = newCoinedWord[searchTextField.text!]
        view.endEditing(true)
    }

    // MARK: - view 탭시 (키보드가 올라와있다면) 키보드를 내려줌
    @IBAction func tapGestureClicked(_ sender: UITapGestureRecognizer) {
        view.endEditing(true)
    }
}

 

<TO-BE>

import UIKit

enum NewCoinedWord: String, CustomStringConvertible, CaseIterable {
    case 윰차
    case 알잘딱깔쎈
    case 내또출
    case H워얼V
    case 많관부
    case 회의주의자
    case 글설리
    case Whyrano
    case 너뭐돼
    case 당모치
    case 돼지런하다
    case 무물
    
    var description: String {
        switch self {
        case .윰차: return "유명인과 무명인을 차별한다는 뜻"
        case .알잘딱깔쎈: return "알아서 잘! 깔끔하고 센스있게~!"
        case .내또출: return "내일 또 출근한다"
        case .H워얼V: return "사랑한다는 뜻. 사랑해의 형태를 뒤집어서 표현한 것"
        case .많관부: return "'많은 관심 부탁드립니다'의 줄임말"
        case .회의주의자: return "뻑하면 회의하자고 하는 직장인"
        case .글설리: return "글쓴이를 설레게 하는 리플"
        case .Whyrano: return "왜이러냐의 사투리 표현인 와이라노를 영어로 적은 말"
        case .너뭐돼: return "'너가 혹시 뭐라도 돼? 라는 뜻으로 유튜버 레오제이님으로 유명해진 유행어"
        case .당모치: return "당연히 모든 치킨은 옳다"
        case .돼지런하다: return "평소에는 행동이 느린데 먹을 때만 엄청 부지런하다"
        case .무물: return "무엇이든 물어보세요"
        }
    }
}

class HomeViewController: UIViewController, UITextFieldDelegate {
    
    @IBOutlet weak var searchTextField: UITextField!
    @IBOutlet var hashTags: [UIButton]!
    @IBOutlet weak var resultLabel: UILabel!
    
    var word1: NewCoinedWord = .윰차
    var word2: NewCoinedWord = .알잘딱깔쎈
    var word3: NewCoinedWord = .내또출
    var word4: NewCoinedWord = .H워얼V
    var word5: NewCoinedWord = .많관부
    var word6: NewCoinedWord = .회의주의자
    var word7: NewCoinedWord = .글설리
    var word8: NewCoinedWord = .Whyrano
    var word9: NewCoinedWord = .너뭐돼
    var word10: NewCoinedWord = .당모치
    var word11: NewCoinedWord = .돼지런하다
    var word12: NewCoinedWord = .무물
    
    override func viewDidLoad() {
        super.viewDidLoad()
        changeNewCoinedWordRandom()
        setUI()
        searchTextField.delegate = self
    }
    
    func setUI() {
        // 검색 텍스트 필드 설정
        searchTextField.keyboardType = .default
        searchTextField.backgroundColor = UIColor.white
        searchTextField.borderStyle = .line
        searchTextField.layer.borderColor = UIColor.black.cgColor
        searchTextField.attributedPlaceholder = NSAttributedString(string: "신조어를 입력해주세요!", attributes: [NSAttributedString.Key.foregroundColor : UIColor.lightGray])
        searchTextField.autocorrectionType = .no
        searchTextField.leftPadding()

        // hashTags ui 설정
        for i in hashTags {
            i.backgroundColor = .white
            i.layer.borderWidth = 1
            i.layer.borderColor = UIColor.black.cgColor
            i.setTitleColor(.black, for: .normal)
        }

        // 결과라벨
        resultLabel.textColor = .black
        resultLabel.font = UIFont.systemFont(ofSize: 18)
        resultLabel.text = "신조어의 의미를 알아봅시다!"
    }
    
    // MARK: - 검색버튼 클릭시
    @IBAction func searchButtonTapped(_ sender: UIButton) {
        searchLogic()
        changeNewCoinedWordRandom()
    }
    
    // MARK: - 키보드 엔터키 클릭시
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        searchLogic()
        changeNewCoinedWordRandom()
        return true
    }
    
    // MARK: - 신조어 검색 로직 및 키보드 내리기
    func searchLogic() {
        
        let text = searchTextField.text
        
        switch text {
        case word1.rawValue:
            resultLabel.text = word1.description
        case word2.rawValue:
            resultLabel.text = word2.description
        case word3.rawValue:
            resultLabel.text = word3.description
        case word4.rawValue:
            resultLabel.text = word4.description
        case word5.rawValue:
            resultLabel.text = word5.description
        case word6.rawValue:
            resultLabel.text = word6.description
        case word7.rawValue:
            resultLabel.text = word7.description
        case word8.rawValue:
            resultLabel.text = word8.description
        case word9.rawValue:
            resultLabel.text = word9.description
        case word10.rawValue:
            resultLabel.text = word10.description
        case word11.rawValue:
            resultLabel.text = word11.description
        case word12.rawValue:
            resultLabel.text = word12.description
        default:
            resultLabel.text = "검색 결과가 없습니다. 다른 신조어를 검색해주세요."
        }
        view.endEditing(true)
    }
    
        // MARK: - 신조어 예제 해시테그 랜덤표기
    func changeNewCoinedWordRandom() {
        // 신조어 키값 4개 랜덤 추출
        var randomKeys: [String] = []
        
        while randomKeys.count < 4 {
            let randomkey = NewCoinedWord.allCases.randomElement()!
            print(randomkey)
            
            if !randomKeys.contains(randomkey.rawValue) {
                randomKeys.append(randomkey.rawValue)
             }
             print(randomKeys.sorted())
        }
    
        // 버튼 4개에 반복 적용
        for i in 0...3 {
            hashTags[i].setTitle("\(randomKeys[i])", for: .normal)
            hashTags[i].setTitleColor(.black, for: .normal)
            hashTags[i].backgroundColor = .white
            hashTags[i].layer.cornerRadius = 8
            hashTags[i].clipsToBounds = true
            hashTags[i].layer.borderWidth = 1
            hashTags[i].layer.borderColor = UIColor.black.cgColor
        }
    }
        
    // MARK: - view 탭시 (키보드가 올라와있다면) 키보드를 내려줌
    @IBAction func tapGestureClicked(_ sender: UITapGestureRecognizer) {
        view.endEditing(true)
    }
}

 

 


오늘의 소감

코드를 짤 때 enum 및 switch구문이 필요한 경우와 tag사용이 필요한 경우에 대한 구분을 좀 더 생각해볼 필요가 있겠다.

tag사용법을 처음 알게되어 앞으로도 종종 적절한 상황에 잘 사용하고 싶다.

2), 3) 과제로직 중 함수의 반환값을 사용한 개선사항이 더 있을 것 같은데, 아직 잘 그려지지 않는다.

다른 새싹분들은 어떻게 구현했는지 궁금하다~!

 

개인적으로 문자열 보간법을 사용해서 그때그때 필요한 값을 (변수명을 입력하거나 i등을 활용해서) 유동적으로 출력할 수 있다는 점이 마음에 든다.

그래서 문자열 보간법 사용에 손이 잘 가는 것 같다.

 

데일리 과제는 아직까지 잘 하고 있는데, Mission사항까지  깊게 알아보지 못해서 아쉽다.

좀더 빠르게 과제를 끝내고 mission도 놓치지 않도록 시간분배 잘해야겠다!

 

 

참고자료

[1] https://www.howtodoitinswift.com/blog/2018/10/19/how-to-get-a-random-enum-value-from-custom-enum-type

 

'TIL(Today I Learned)' 카테고리의 다른 글

[TIL] 2022.07.14 (SeSAC iOS)  (0) 2022.07.14
[TIL] 2022.07.13 (SeSAC iOS)  (0) 2022.07.13
[TIL] 2022.07.11 (SeSAC iOS)  (0) 2022.07.11
[TIL] 2022.07.09~10 (SeSAC iOS)  (0) 2022.07.11
[TIL] 2022.07.08 (SeSAC iOS)  (0) 2022.07.08