주니곰의 괴발노트
SeSAC TIL - 22.07.12 본문
1. 오늘 배운 내용
- 문법을 위주로 살펴보는 시간을 가졌습니다. (열거형 등)
- 그리고 함수의 세부적인 활용법(입, 출력 값이 있을 때 및 출력 값이 있을 때 활용법 등)에 대해 배웠습니다.
2. Checklist
2-1. ValueChanged (feat. Switch, Slider, datePicker)
ValueChanged Action으로 각 요소들을 뷰컨트롤러와 연결할 경우, 스위치의 경우는 Boolean 타입이기 때문에 on과 off의 두 값만 존재합니다. 하지만 슬라이더의 경우, Float 타입으로 값이 주어지기 때문에 이를 활용해서 비율로도 표현이 가능합니다. datePicker의 경우는 선택했을 때 해당 날짜값이 전달됩니다.
2-2. View: tag, alpha, opacity
tag - 태그는 버튼을 IBAction과 연결할 때 활용할 수 있습니다. 같은 액션으로 연결될 경우, 각 버튼태그에 다른 인텍스값을 주어 어떤 버튼이 눌렸는지 구분할 때 활용할 수 있습니다.
alpha와 opacity 모두 각 요소의 투명도를 나타냅니다. 하지만 이 둘의 큰 차이점은 내부를 같이 투명하게 하는지 안하는지의 차이에 있습니다.
2-3. Enumeration
열거형은 관련이 있는 값들의 그룹이며 코드에 타입 안정성을 주는 기본 타입입니다. 열거형은 그 자체가 일급객체이고 전통적으로 클래스에서 지원하느 많은 부분을 채택하고 있습니다. 스위치문과 주로 같이 쓰이고, 모든 경우를 처리할 경우, 스위치문에서 default 케이스는 활용하지 않아도 괜찮습니다. 이를 활용하면 보다 편하게 각 케이스를 구분지을 수 있는 코드를 작성할 수 있습니다.
2-4. RawValue
열거형을 관계 있는 다른 타입의 값을 담을 수 있도록 선언할 수 있습니다. 열거형은 모두 같은 타입인 기본값 혹은 원시값이라고 하는 것들로 미리 채워질 수 있습니다. 원시값은 String, Int 등의 타입이 될 수 있으며, .rawValue 로 원시값을 호출할 수 있습니다.
2-5. Print Vs Return
Print와 Return은 다른 수행을 합니다. Print는 주어진 데이터를 디버그 영역에 표시하는 역할을 수행합니다. Return은 함수가 포함하고 있는 코드를 실행한 후 결과값을 전달하는 역할을 합니다. 할수를 받아서 변수에 할당할 수도 있고 함수를 Return할 수도 있습니다.
2-6. Tuple
튜플은 어떤 연관된 값들의 모임입니다. String, Int, Bool 등이 올 수도 있고, 다른 튜플도 담을 수 있습니다. 튜플에 전달되는 값은 참조가 아닌 값이 옵니다. 튜플을 사용할 때는 dot syntax로 tuple.0 등처럼 값에 접근할 수 있습니다.
2-7. 함수의 반환값 (feat. shuffle Vs shuffled, subtract Vs subtracting, append Vs appending, etc)
함수의 반환값에 대해 주로 쓰는 함수가 있는데 바로 sort(), reverse(), shuffle() 등입니다. 이 함수들의 형태를 보면, 동사원형의 형태와 분사 형태가 있는데(-ed, -ing) 애플의 개발자 문서에도 알 수 있듯이, 대부분 분사형태의 함수는 리턴값이 있습니다. 따라서 동사원형의 함수는 어떤 변수에 선언한 내용 자체가 변경되지만 분사형태의 함수는 원형은 건들지 않고 리턴값을 전달한다는 것을 파악할 수 있습니다.
2-8. RawString
#을 사용해서 String을 사용하는 것을 커스텀할 수 있습니다. 보통의 경우 백슬래쉬( \ )를 쓰고 그 뒤에 정해진 특수 문자를 써야 그 문자가 반영이 됐지만, 이 경우 문자열 앞뒤에 #만 붙이면 중간에 백슬래쉬를 쓰지 않고 보다 쉽게 사용할 수 있습니다. 중요한 것은 #의 개수는 중요하지 않으며 반드시 앞뒤로 #의 개수를 맞춰야 합니다. 여러 줄로 사용하고 싶을 때는 맨 첫줄에 (#""")를 입력하고 가장 마지막 줄에 ("""#)를 입력해서 사용가능합니다. 중간에 문자열 보간법을 사용하려고 한다면 \#를 활용하여 사용해야 합니다.
2-9 Override Vs Overload
Override - Override는 하위클래스가 상위클래스를 상속하면서 상위클래스에 있던 function을 그대로 사용하려고 할 때 사용합니다. 이를 통해 하위클래스는 상위클래스의 멤버에 바로 접근 가능합니다. 이렇게 사용해야 하는 이유는 아마도 클래스가 상속이라는 개념을 가지고 있고, 상위클래스와 하위클래스 모두 같은 함수를 가지다 보니, 동일 함수를 실행하는 과정에서 발생하는 문제를 줄이기 위한 방법이 아닐까 생각합니다.
overload - 오버로딩은 같은 이름을 가진 함수를 다양한 형태로 만들어 사용가능한 개념을 의미합니다. 리턴이 없는 함수로 만들 수도 있으며, 여러 타입의 함수를 한 이름에 만들 수 있습니다. 오버로딩된 함수는 반드시 다른 파라미터를 가지고 있어야 합니다.
3. 과제 및 실습
코드 개선해보기(감정 다이어리, 신조어 검색기)
- 신조어 검색기를 열거형을 이용하여 코드를 개선해보았습니다.
- 열거형을 클래스 밖에 두었고, 열거형의 케이스 이름 자체를 원시값으로 활용, 내부에 변수를 두어 변수 호출 시, 의미를 리턴하도록 구성하였습니다.
- 이 과정에서 열거형 사용에 익숙하지 않아, 인스턴스를 생성하지 않고 열거형을 정의한 후, 바로 사용하려고 해서 코드를 구성하는 데 애를 먹었습니다.
import UIKit
enum Newlang: String, CustomStringConvertible {
case 스불재
case 억텐
case 쫌쫌따리
case 점메추
case 킹받다
case 군싹
case 갓생
case 오히려좋아
case 웃안웃
case 쩝쩝박사
var description: String {
switch self {
case .스불재: return "스스로 불러온 재앙의 줄임말로 자신이 계획한 일로 자신이 고통받을 때 사용한다."
case .억텐: return "억지 텐션의 줄임말로 억지로 텐션을 올려서 발랄하게 할 때 사용한다."
case .쫌쫌따리: return "아주 조금씩 하찮은 양을 모으는 모습"
case .점메추: return "점심 메뉴 추천"
case .킹받다: return "열받다는 뜻으로 킹을 붙여 강조한 의미. 자매품으로 킹받드라슈가 있음"
case .군싹: return "군침이 싹 도네의 줄임말로 뽀로로 루피 짤과 함께 퍼지기 시작한 신조어."
case .갓생: return "신을 뜻하는 갓(God)과 인생을 합친 말로 부지런하고 남의 모범이 되는 삶을 사는 것을 의미한다."
case .오히려좋아: return "좋지 않은 상황임에도 좋은 점을 찾아낼 때 쓰는 말"
case .웃안웃: return "웃긴데 안 웃겨의 줄임말로 웃기지만 슬픈, 웃기지만 웃기지만은 않은 상황을 말하는 것을 의미한다."
case .쩝쩝박사: return "음식의 맛있는 조합을 잘 아는 사람을 칭찬할 때 쓰는 말"
}
}
}
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var searchTextField: UITextField!
@IBOutlet weak var searchButton: UIButton!
@IBOutlet weak var exButton1: UIButton!
@IBOutlet weak var exButton2: UIButton!
@IBOutlet weak var exButton3: UIButton!
@IBOutlet weak var exButton4: UIButton!
@IBOutlet weak var answerLabel: UILabel!
var lang1: Newlang = .스불재
var lang2: Newlang = .억텐
var lang3: Newlang = .쫌쫌따리
var lang4: Newlang = .점메추
var lang5: Newlang = .킹받다
var lang6: Newlang = .군싹
var lang7: Newlang = .갓생
var lang8: Newlang = .오히려좋아
var lang9: Newlang = .웃안웃
var lang10: Newlang = .쩝쩝박사
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - Helper Functions
func configureUI() {
configureTextField()
configureExButtons(exButton1, titles: "스불재")
configureExButtons(exButton2, titles: "억텐")
configureExButtons(exButton3, titles: "쫌쫌따리")
configureExButtons(exButton4, titles: "점메추")
configureAnswerLabel()
}
func configureExButtons(_ buttons: UIButton, titles: String) {
buttons.setTitle(titles, for: .normal)
buttons.setTitleColor(.black, for: .normal)
buttons.layer.cornerRadius = 8
buttons.clipsToBounds = true
buttons.layer.borderColor = UIColor.black.cgColor
buttons.layer.borderWidth = 0.8
}
func configureTextField() {
searchTextField.layer.borderColor = UIColor.black.cgColor
searchTextField.layer.borderWidth = 4
searchTextField.textAlignment = .left
searchTextField.returnKeyType = .search
}
func configureAnswerLabel() {
answerLabel.textAlignment = .center
answerLabel.font = UIFont.systemFont(ofSize: 18)
answerLabel.textColor = .black
answerLabel.numberOfLines = 3
}
// MARK: - IBActions
@IBAction func searchButtonTapped(_ sender: UIButton) {
let text = searchTextField.text?.components(separatedBy: [" ", ".", ",", "!", "?"]).joined()
switch text {
case lang1.rawValue:
answerLabel.text = lang1.description
case lang2.rawValue:
answerLabel.text = lang2.description
case lang3.rawValue:
answerLabel.text = lang3.description
case lang4.rawValue:
answerLabel.text = lang4.description
case lang5.rawValue:
answerLabel.text = lang5.description
case lang6.rawValue:
answerLabel.text = lang6.description
case lang7.rawValue:
answerLabel.text = lang7.description
case lang8.rawValue:
answerLabel.text = lang8.description
case lang9.rawValue:
answerLabel.text = lang9.description
case lang10.rawValue:
answerLabel.text = lang10.description
default:
answerLabel.text = "검색 결과 없음"
}
}
@IBAction func rootViewTapped(_ sender: UITapGestureRecognizer) {
view.endEditing(true)
}
@IBAction func exButtonTapped(_ sender: UIButton) {
switch sender {
case exButton1:
answerLabel.text = lang1.description
case exButton2:
answerLabel.text = lang2.description
case exButton3:
answerLabel.text = lang3.description
case exButton4:
answerLabel.text = lang4.description
default:
answerLabel.text = "검색결과 없음"
}
}
@IBAction func searchKeyTapped(_ sender: UITextField) {
let text = searchTextField.text?.components(separatedBy: [" ", ".", ",", "!", "?", "*", "@", "~", "`"]).joined()
switch text {
case lang1.rawValue:
answerLabel.text = lang1.description
case lang2.rawValue:
answerLabel.text = lang2.description
case lang3.rawValue:
answerLabel.text = lang3.description
case lang4.rawValue:
answerLabel.text = lang4.description
case lang5.rawValue:
answerLabel.text = lang5.description
case lang6.rawValue:
answerLabel.text = lang6.description
case lang7.rawValue:
answerLabel.text = lang7.description
case lang8.rawValue:
answerLabel.text = lang8.description
case lang9.rawValue:
answerLabel.text = lang9.description
case lang10.rawValue:
answerLabel.text = lang10.description
default:
answerLabel.text = "검색 결과 없음"
}
view.endEditing(true)
}
}
- 감정 다이어리를 열거형을 이용하여 코드를 개선해보았습니다.
- 감정 다이어리에 활용되는 이미지의 이름, 버튼을 누른 횟수, 버튼의 감정을 튜플이 들어간 배열 형태로 담았고 마찬가지로 열거형을 사용하여, 원시값은 감정의 이름, 변수에는 이미지 파일명이 리턴되도록 선언하였습니다.
- 그 이외에는 전에 활용했던 코드와 유사합니다.
- 열거형을 사용하면서 느낀 것은 자주 활용하는 데이터가 많다면 열거형으로 선언해두고 간단하게 호출하여 빠르고 간결하게 코드를 구성할 수 있을 것 같다는 생각이 들었습니다.
import UIKit
enum Emotions: String, CustomStringConvertible {
case 행복해
case 사랑해
case 좋아해
case 당황해
case 속상해
case 우울해
case 심심해
case 아파해
case 슬퍼해
var description: String {
switch self {
case .행복해: return "sesac_slime1"
case .사랑해: return "sesac_slime2"
case .좋아해: return "sesac_slime3"
case .당황해: return "sesac_slime4"
case .속상해: return "sesac_slime5"
case .우울해: return "sesac_slime6"
case .심심해: return "sesac_slime7"
case .아파해: return "sesac_slime8"
case .슬퍼해: return "sesac_slime9"
}
}
}
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var oneImageButton: UIButton!
@IBOutlet weak var twoImageButton: UIButton!
@IBOutlet weak var threeImageButton: UIButton!
@IBOutlet weak var fourImageButton: UIButton!
@IBOutlet weak var fiveImageButton: UIButton!
@IBOutlet weak var sixImageButton: UIButton!
@IBOutlet weak var sevenImageButton: UIButton!
@IBOutlet weak var eightImageButton: UIButton!
@IBOutlet weak var nineImageButton: UIButton!
@IBOutlet var buttonsArray: [UIButton]!
@IBOutlet weak var oneLabel: UILabel!
@IBOutlet weak var twoLabel: UILabel!
@IBOutlet weak var threeLabel: UILabel!
@IBOutlet weak var fourLabel: UILabel!
@IBOutlet weak var fiveLabel: UILabel!
@IBOutlet weak var sixLabel: UILabel!
@IBOutlet weak var sevenLabel: UILabel!
@IBOutlet weak var eightLabel: UILabel!
@IBOutlet weak var nineLabel: UILabel!
@IBOutlet var labelsArray: [UILabel]!
var emoArray = [(Emotions.행복해.rawValue, Emotions.행복해.description, 0),
(Emotions.사랑해.rawValue, Emotions.사랑해.description, 0),
(Emotions.좋아해.rawValue, Emotions.좋아해.description, 0),
(Emotions.당황해.rawValue, Emotions.당황해.description, 0),
(Emotions.속상해.rawValue, Emotions.속상해.description, 0),
(Emotions.우울해.rawValue, Emotions.우울해.description, 0),
(Emotions.심심해.rawValue, Emotions.심심해.description, 0),
(Emotions.아파해.rawValue, Emotions.아파해.description, 0),
(Emotions.슬퍼해.rawValue, Emotions.슬퍼해.description, 0)]
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - Helper Functions
func configureUI() {
configureButtons(oneImageButton, image: emoArray[0].1, title: emoArray[0].0)
configureButtons(twoImageButton, image: emoArray[1].1, title: emoArray[1].0)
configureButtons(threeImageButton, image: emoArray[2].1, title: emoArray[2].0)
configureButtons(fourImageButton, image: emoArray[3].1, title: emoArray[3].0)
configureButtons(fiveImageButton, image: emoArray[4].1, title: emoArray[4].0)
configureButtons(sixImageButton, image: emoArray[5].1, title: emoArray[5].0)
configureButtons(sevenImageButton, image: emoArray[6].1, title: emoArray[6].0)
configureButtons(eightImageButton, image: emoArray[7].1, title: emoArray[7].0)
configureButtons(nineImageButton, image: emoArray[8].1, title: emoArray[8].0)
configureLabels(oneLabel, emotion: emoArray[0].0, counts: emoArray[0].2)
configureLabels(twoLabel, emotion: emoArray[1].0, counts: emoArray[1].2)
configureLabels(threeLabel, emotion: emoArray[2].0, counts: emoArray[2].2)
configureLabels(fourLabel, emotion: emoArray[3].0, counts: emoArray[3].2)
configureLabels(fiveLabel, emotion: emoArray[4].0, counts: emoArray[4].2)
configureLabels(sixLabel, emotion: emoArray[5].0, counts: emoArray[5].2)
configureLabels(sevenLabel, emotion: emoArray[6].0, counts: emoArray[6].2)
configureLabels(eightLabel, emotion: emoArray[7].0, counts: emoArray[7].2)
configureLabels(nineLabel, emotion: emoArray[8].0, counts: emoArray[8].2)
}
func configureButtons(_ button: UIButton, image: String, title: String) {
button.setTitle(title, for: .normal)
button.setImage(UIImage(named: image), for: .normal)
}
func configureLabels(_ label: UILabel, emotion: String, counts: Int) {
label.text = "\(emotion) \(counts)"
label.textAlignment = .center
}
// MARK: - IBActions
@IBAction func emotionButtonTapped(_ sender: UIButton) {
switch sender.currentTitle ?? "" {
case emoArray[0].0:
emoArray[0].2 += 1
labelsArray[0].text = "\(emoArray[0].0) \(emoArray[0].2)"
case emoArray[1].0:
emoArray[1].2 += 1
labelsArray[1].text = "\(emoArray[1].0) \(emoArray[1].2)"
case emoArray[2].0:
emoArray[2].2 += 1
labelsArray[2].text = "\(emoArray[2].0) \(emoArray[2].2)"
case emoArray[3].0:
emoArray[3].2 += 1
labelsArray[3].text = "\(emoArray[3].0) \(emoArray[3].2)"
case emoArray[4].0:
emoArray[4].2 += 1
labelsArray[4].text = "\(emoArray[4].0) \(emoArray[4].2)"
case emoArray[5].0:
emoArray[5].2 += 1
labelsArray[5].text = "\(emoArray[5].0) \(emoArray[5].2)"
case emoArray[6].0:
emoArray[6].2 += 1
labelsArray[6].text = "\(emoArray[6].0) \(emoArray[6].2)"
case emoArray[7].0:
emoArray[7].2 += 1
labelsArray[7].text = "\(emoArray[7].0) \(emoArray[7].2)"
case emoArray[8].0:
emoArray[8].2 += 1
labelsArray[8].text = "\(emoArray[8].0) \(emoArray[8].2)"
default:
break
}
}
}
4. 자료 출처
구글 검색어: slider valuechanged in swift -> https://developer.apple.com/documentation/uikit/uislider
구글 검색어: enumeration in swift -> https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html
구글 검색어: difference between print and return in swift -> https://www.hackingwithswift.com/forums/swift/about-print-and-return-what-makes-them-different-from-each-other/1382
구글 검색어: tuple in swift -> https://medium.com/swift-programming/swift-tuple-328aecff50e7
구글 검색어: shuffled in swift -> https://developer.apple.com/documentation/swift/array/shuffle()
구글 검색어: rawstring in swift -> https://www.hackingwithswift.com/articles/162/how-to-use-raw-strings-in-swift
구글 검색어: override in swift -> https://www.programiz.com/swift-programming/overriding
구글 검색어: overloading in swift -> https://www.programiz.com/swift-programming/function-overloading
'기타' 카테고리의 다른 글
SeSAC TIL - 22.07.14 (0) | 2022.07.18 |
---|---|
SeSAC TIL - 22.07.13 (0) | 2022.07.18 |
SeSAC TIL - 22.07.11 (0) | 2022.07.17 |
SeSAC TIL - 22.07.08 (0) | 2022.07.17 |
SeSAC TIL - 22.07.07 (0) | 2022.07.14 |