오늘은 알고리즘 문제를 해결하면서 발생한 오류를 수정하고,
앱 개발 입문 강의를 들으며, 개발에서 중요한 개념인 SceneDelegate
와
코드베이스 기반 실습을 진행하며, 서드파티 라이브러리인 SnapKit
을 공부했다.
오래전 유행했던 콜라 문제가 있다.
콜라 빈 병 a
개를 가져가면 b
개의 새 콜라를 받을 수 있을 때, n
개의 빈 병을 처음 가지고 있다면 총 몇 개의 콜라를 받을 수 있는지 계산하는 문제이다.
import Foundation
func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle: Int = n // 가지고 있는 빈병
var newCoke: Int = 0 // 새로 받는 콜라
var rest: Int = 0// 나머지
var totalNewCoke: Int = 0 // 새로받은 모든 콜라의 개수
while true {
rest = emptyBottle % a // 새로 받은 콜라를 a로 나눈 나머지
newCoke = emptyBottle / a // 새로 받은 콜라 a로 나눈 몫
if newCoke == 0 { // 새로 받은 콜라가 없으면 종료
break
}
if rest != 0 { // 교환 받지 못한 빈병이 있을때
//totalNewCoke = totalNewCoke + newCoke + rest
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke + rest // 빈병에 더하기
} else {
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke
}
}
return totalNewCoke
}
func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle: Int = n // 가지고 있는 빈병
var newCoke: Int = 0 // 새로 받는 콜라
var rest: Int = 0// 나머지
var totalNewCoke: Int = 0 // 새로받은 모든 콜라의 개수
while true {
rest = emptyBottle % a // 새로 받은 콜라를 a로 나눈 나머지
newCoke = emptyBottle / a // 새로 받은 콜라 a로 나눈 몫
if rest != 0 { // 교환 받지 못한 빈병이 있을때
//totalNewCoke = totalNewCoke + newCoke + rest
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke + rest // 빈병에 더하기
} else {
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke
}
if emptyBottle < a {
break
}
}
return totalNewCoke
}
newCoke == 0
👉 newCoke == 0
func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle: Int = n // 가지고 있는 빈병
var newCoke: Int = 0 // 새로 받는 콜라
var rest: Int = 0// 나머지
var totalNewCoke: Int = 0 // 새로받은 모든 콜라의 개수
while emptyBottle >= a {
rest = emptyBottle % a // 새로 받은 콜라를 a로 나눈 나머지
newCoke = emptyBottle / a // 새로 받은 콜라 a로 나눈 몫
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke + rest // 빈병에 더하기
}
return totalNewCoke
}
while emptyBottle >= a
if문
제거작성한 코드에서 다음과 같은 실수를 발견했다.
newCoke = emptyBottle / a
은 단순히 새 콜라를 받기 위해 줘야되는 빈병의 수로만 나눔!!!!!!!a
로 나누고 새로 받는 콜라의 갯수 b
를 곱하지 않았다.(newCoke = emptyBottle / a) * b
가 되어야 됨func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle: Int = n // 가지고 있는 빈병
var newCoke: Int = 0 // 새로 받는 콜라
var rest: Int = 0// 나머지
var totalNewCoke: Int = 0 // 새로받은 모든 콜라의 개수
while emptyBottle >= a {
rest = emptyBottle % a * b// 새로 받은 콜라를 a로 나눈 나머지
newCoke = emptyBottle / a // 새로 받은 콜라 a로 나눈 몫
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke + rest // 빈병에 더하기
}
return totalNewCoke
}
a
로 나눈 몫(emptyBottle / a
)을 b
와 곱하여 새로운 콜라 개수를 구함.emptyBottle % a
)를 계산하여 빈 병 개수를 갱신.while
루프를 통해 빈 병이 부족할 때까지 반복.최종적으로 이 방법으로 올바른 결과를 얻을 수 있었다.
혼자서 생각 못하고 지피티한테 물어봐서 왜 틀리는지 알아냄...멍청멍청😳😭😩🫣
import Foundation
func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle: Int = n // 가지고 있는 빈병
var newCoke: Int = 0 // 새로 받는 콜라
var rest: Int = 0// 나머지
var totalNewCoke: Int = 0 // 새로받은 모든 콜라의 개수
while emptyBottle >= a {
rest = emptyBottle % a // 새로 받은 콜라를 a로 나눈 나머지
newCoke = (emptyBottle / a) * b // 새로 받은 콜라 a로 나눈 몫
totalNewCoke = totalNewCoke + newCoke
emptyBottle = newCoke + rest // 빈병에 더하기
}
return totalNewCoke
}
func solution(_ a:Int, _ b:Int, _ n:Int) -> Int {
var emptyBottle = n // 현재 가지고 있는 빈 병 개수
var totalNewCoke = 0 // 총 받은 콜라 개수
while emptyBottle >= a { // 빈 병 개수가 교환 기준(a)보다 많을 때만 반복
let newCoke = (emptyBottle / a) * b // 교환으로 받은 콜라 개수
totalNewCoke += newCoke // 받은 콜라 개수 더하기
emptyBottle = (emptyBottle % a) + newCoke // 남은 빈 병 + 새로 받은 콜라의 빈 병
}
return totalNewCoke
}
window
의 역할앱 개발을 하면서 SceneDelegate
에서 var window: UIWindow?
가 무엇인지 이해하는 것이 중요했다.
window
란? (아직 잘 모르겠다...)ViewController
를 루트 뷰로 설정하는 역할scene(_:willConnectTo:options:)
코드 분석앱 실행 시 첫 화면을 설정하는 중요한 함수이다.
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
// `scene`을 UIWindowScene으로 변환 (iPadOS 및 다중 윈도우 지원을 위해 필요)
guard let windowScene = (scene as? UIWindowScene) else { return }
// 새로운 UIWindow 생성 (앱의 UI를 표시할 창)
let window = UIWindow(windowScene: windowScene)
// 앱의 첫 번째 화면을 담당할 루트 뷰 컨트롤러 설정
window.rootViewController = ViewController()
// 화면에 창을 표시
window.makeKeyAndVisible()
// 생성한 window를 SceneDelegate의 window 변수에 저장
self.window = window
}
scene
을 UIWindowScene
으로 변환하여 다중 윈도우를 지원하도록 처리.UIWindow
를 생성하여 앱의 UI를 표시할 창을 준비.rootViewController
를 설정하여 앱의 첫 화면을 표시.makeKeyAndVisible()
을 호출하여 창을 활성화.scene을 UIWindowScene으로 변환
새로운 UIWindow 생성
루트 뷰 컨트롤러 설정
창을 활성화하고 표시
self.window에 저장
오토레이아웃을 코드로 설정하는 것은 번거롭지만, SnapKit
을 사용하면 훨씬 간결하게 작성할 수 있다.
NSLayoutConstraint
보다 훨씬 직관적let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
label.widthAnchor.constraint(equalToConstant: 200),
label.heightAnchor.constraint(equalToConstant: 50)
])
import SnapKit
let label = UILabel()
view.addSubview(label)
label.snp.makeConstraints { make in
make.center.equalToSuperview()
make.width.equalTo(200)
make.height.equalTo(50)
}
import UIKit
class ViewController: UIViewController {
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
private func configureUI() {
view.backgroundColor = .white
label.text = "안녕하세요"
label.textColor = .black
view.addSubview(label)
// Snapkit을 사용하면 label.translatesAutoresizingMaskIntoConstraints = false 사용 안해도 됨
label.snp.makeConstraints {
$0.width.equalTo(80)
$0.height.equalTo(40)
$0.center.equalToSuperview()
}
}
}
import UIKit
class ViewController: UIViewController {
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
private func configureUI() {
view.backgroundColor = .white
button.setTitle("Click", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .red
button.layer.cornerRadius = 10
view.addSubview(button)
button.snp.makeConstraints {
$0.width.equalTo(120)
$0.height.equalTo(60)
$0.center.equalToSuperview()
}
}
}
import UIKit
class ViewController: UIViewController {
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
private func configureUI() {
view.backgroundColor = .white
imageView.image = UIImage(named: "cat")
imageView.backgroundColor = .black
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.snp.makeConstraints {
$0.width.height.equalTo(300)
$0.center.equalToSuperview()
}
}
}
메서드 | 설명 |
---|---|
make.edges.equalToSuperview() | 부모 뷰와 동일한 크기 설정 |
make.center.equalToSuperview() | 부모 뷰의 중앙 정렬 |
make.top.equalTo(view.safeAreaLayoutGuide.snp.top) | Safe Area의 상단에 맞춤 |
make.width.equalTo(100) | 너비를 100으로 설정 |
make.height.equalToSuperview().multipliedBy(0.5) | 부모 뷰의 50% 크기로 설정 |
SceneDelegate
에서 window
가 하는 역할과 앱의 첫 화면을 설정하는 방법을 익혔다.