
TIL 6일차 - 타입 안정성 개선하기
팀 프로젝트 마지막 발표준비되어 가는 과정 중에 튜터님이 오셔서 깜짝 코드리뷰를 해주셨다.
매도 일찍 맞는 게 좋다고 발표전에 완벽!!(?) 하게 정리하고 갈 수 있어서 너무 좋은 기회였던 것 같다 ㅎㅎ
이미지 변수 선언 과정에서 String 배열에서 UIImage? 배열로 변경하라고 리뷰해 주셨다.. 근데 왜일까?
// 이미지 파일 이름 문자열로 나열한 배열 (수정 전)
// "profile1" 같은 문자열(String) 만 저장
// 실제 이미지는 아직 메모리에 없음
private let imageNames = ["profile1", "profile2", "profile3"]
// 이미지 파일을 UIImage로 바로 로드해 저장한 배열 (수정 후)
// .profile1은 Asset Catalog에 등록된 이미지를 UIImage로 바로 로드한 배열
private let images: [UIImage?] = [.profile1, .profile2, .profile3]
수정 전 코드는 이미지를 나중에 직접 UIImage(named:)로 꺼내 써야 한다.
"Hard-coded String(문자열 직접 입력)" 방식 대신, Swift의 정적 속성(Static properties)이나 Asset Symbol을 사용하여 오타를 방지하고 자동 완성을 활용하라는 뜻이다.
그리고 현재 코드에서 imageNames = ["profile1", "profile2", "profile3"]처럼 문자열로 관리하면, 나중에 asset 이름이 바뀌거나 오타가 나도 컴파일 시점에 알 수 없고 런타임에서 nil 오류로 터진다.
또 코드 읽는 사람이 “이게 이미지인가?” 바로 알기 어려워 가독성이 똥💩이다.
수정 후의 코드는
이미지가 이미 로드된 상태로
오타 나면 컴파일 단계에서 바로 에러가 난다. 컴파일 에러😍>>>>>>>런타임 에러🤮
코드만 딱 봐도 아, 이미지 배열이구나!!! 하고 바로 이해되고 반복 사용하기 훨씬 깔끔하다.
그리고 이미지 자체를 처음부터 저장하므로 사용 시 바로 imageView에 할당이 가능하다.
그런데 여기서 드는 추가 의문.. 왜?? 왜 타입이 [UIImage?] 일까?
[UIImage?]
이유는 하나다.
-> Asset에 이미지가 없을 수도 있음 즉. profile1→ nil 이 가능하므로 옵셔널로 처리해야 한다.
참 배우면서 느끼는 게 스위프트 정말 철저하고 깐깐하다.. 애플다움
따라서 수정 후엔 UIImage(named: ) 안 해줘도 되고 바로 슈가 대입해 주면 된다..
//수정 전: for name in imageNames { ... imageView.image = UIImage(named: name) }
for image in images {
let imageView = UIImageView()
imageView.image = image // 이미 UIImage 객체이므로 image바로 대입!!!!
// ... 이하 동일
}
추가로 버튼 만드는 함수도 같은 논리로 수정하였다.
// 버튼 만드는 함수 만들기 (수정 전)
private func makeIconButton(
imageName: String,
// String을 이용한 문자열 기반 방식
action: @escaping () -> Void
) -> UIButton {
let button = UIButton(type: .system)
button.setImage(
// 문자열로 저장했으므로 UIImage(named:) 로 꺼내써야함
UIImage(named: imageName)?.withRenderingMode(.alwaysOriginal),
for: .normal
)
// 버튼 생성 함수 (수정 후)
private func makeIconButton(
image: UIImage?,
//String 대신 UIImage를 받아 컴파일 단계에서 오류를 방지함
action: @escaping () -> Void
) -> UIButton {
// system 타입 UIButton 생성
let button = UIButton(type: .system)
button.setImage(
// 바로 할당 가능
image?.withRenderingMode(.alwaysOriginal), for: .normal)
// ... 이하 동일
}
이제 위에서 만든 함수를 이용한 단계에서도 수정해 주면 끝난다.
// 함수 이용해 깃허브 버튼 만들기 (수정 전)
let githubButton = makeIconButton(imageName: "githubLogo") {
if let url = URL(string: "https://github.com/coduhee") {
UIApplication.shared.open(url)
}
}
// 함수 이용해 깃허브 버튼 만들기 (수정 후)
let githubButton = makeIconButton(image: .githubLogo) {
if let url = URL(string: "https://github.com/coduhee") {
UIApplication.shared.open(url)
}
}
왜 이렇게 하는지? (코드리뷰의 핵심 이유)
- 안정성: "profile1"을 "proflie1"(오타)로 써도 컴파일러가 잡아주지 못하지만,. profile1은 오타가 나면 즉시 에러를 띄워준다.
- 가독성: 코드를 작성할 때 점(.)만 찍어도 사용 가능한 이미지 목록이 쫙 나와서 훨씬 편해진다.
- 유지보수: 이미지 이름이 바뀌었을 때 extension 부분 한 곳만 수정하면 전체 코드가 다 적용된다.
'iOS > UIkit ' 카테고리의 다른 글
| [iOS-UIKit] 스토리보드 -> 코드베이스 환경설정하는 방법 (0) | 2026.01.22 |
|---|---|
| [iOS] To-do 클론 앱 따라하기 (1) (1) | 2026.01.05 |
| [iOS] KPT 회고 (왜_되는지_모름 팀) (0) | 2026.01.05 |
| [iOS] 팀 소개 앱 프로젝트 개인 페이지 제작기 (0) | 2025.12.30 |
| [iOS] 팀 소개 어플리케이션 프로젝트 (0) | 2025.12.29 |