ggmj-의 등록된 링크

 ggmj-로 등록된 네이버 블로그 포스트 수는 103건입니다.

[GDF ] FireBase 연결하기. [내부링크]

카카오 소셜 로그인 한 유저의 정보를 저장하기 위해 Firebase로 백엔드를 구축해보자. Firebase 프로젝트 추가하기 클릭 이름을 입력하고 이어서 나오는 과정들 계속 버튼을 눌러 넘어가기. iOS 앱으로 추가하기를 클릭 앱등록 칸에서 iOS번들 ID를 입력한다. GoogleService-info.plist를 다운받고 프로젝트를 열어 추가해준다. 추가 시 Create groups와 Target만 체크한 후 Finish CocoaPods로 SDK 설치하기 pod 'Firebase/Analytics' AppDelegate 설정 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // ..... FirebaseApp.configure() // .... }

VM과 VC사이에서 클로저 사용 [내부링크]

ViewModel(VM)과 ViewController(VC) 사이에서 클로저를 사용하는 방식 1. ViewModel (VM)에서의 클로저 클로저 실행 위치 설정: ViewModel에서는 클로저가 언제 실행될지를 정의 self.onLoginSuccess?()는 로그인 프로세스가 성공적으로 완료되었을 때 해당 위치에서 클로저를 실행합니다. 조건부 실행: ViewModel은 클로저가 실제로 설정되어 있을 때만 실행하도록 합니다. 이는 ? (옵셔널 체이닝)을 사용하여 확인합니다. 언제 실행될지 VM에서 설정하기 ( 아래 코드는 카카오 로그인 성공에 따른 클로저 실행 위치) class KakaoAuthVM { var onLoginSuccess: (() -> Void)? var onLoginFailure: (() -> Void)? var onLogout: (() -> Void)? //...... func handleKakaoLogin() { print("VM카카오로그인") // 카카오톡 실행

구글 로그인 연동(feat: 로그인 화면전환) [내부링크]

기존에 생성한 Firebase 프로젝트의 Authentication를 클릭해 제공업체 추가 GoogleService-info.plist를 다운받아 프로젝트에 넣기 해당 파일 안에 들어있는 REVERSED_CLIENT_ID를 URL Types에 넣어준다. 또한 info.plist에 아래 코드를 삽입 <key>GIDClientID</key> <string>GoogleService-Info에 있는 CLIENT_ID를 넣읍시다</string> AppDelegate.swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {} 코드 안에 FirebaseApp.configure()를 넣어준다. 기존의 카카오 로그인 할 때도 여기에 key를 삽입했었다. import Firebase import

.gitignore 설정, API KEY 숨기기, [내부링크]

gitignore를 설정했지만... API Key값이 올라갔다.... 이미 git에서 추적하고 있는 파일은 gitignore에 적용시키려면 캐시를 날리고 다시 커밋해야 적용이 된다는 사실을 망각하고 있었다.. ( 이럴 땐 캐시를 삭제 후 적용해야한다.) git rm -r --cached . git add . git commit -m "fixed untracked files" 이렇게 된거 .gitignore 파일을 만드는 과정부터 API KEY 숨기는 것 까지 블로그에 작성해야겠다. 우선 Empty 파일로 .gitignore를 생성해준다. gitignore 생성 후 아래 깃 코드에서 ignore내용을 붙여 넣거나, https://github.com/github/gitignore/blob/main/Swift.gitignore {"payload":{"allShortcutsEnabled":false,"fileTree":{"":{"items":[{"name":".github","path":"

온보딩 화면 만들기 [내부링크]

안녕하세요? 오랜만에 돌아왔습니다. 오늘은 온보딩 화면을 만들거에요. 튜토리얼 화면으로 활용하면 딱이죠? 우선 스토리 보드를 보여드릴게요 시나리오 로그인을 한다 로그인 완료 시 뷰화면으로 전환 뷰 화면에 접속 시 모달창으로 앱에 대한 설명 제공 설명이 끝나는 시점에 버튼을 삽입해 뷰 화면으로 전환 페이지 시트 class OnBoardViewController: UIPageViewController { lazy var VCArray: [UIViewController] = { return [ self.VCInstance(name: "FirstVC"), self.VCInstance(name: "SecondVC"), self.VCInstance(name: "ThirdVC") ] }() func VCInstance(name: String) -> UIViewController { return UIStoryboard(name: "Main", bundle: nil).instantiateViewCo

MVVM 아키텍처 고민, Protocol, enum [내부링크]

단순히 모델, 뷰, 뷰모델로만 구분하여 작성하는 것에서 더 확장해 네트워크 작업, 화면전환, 인증에 관한 작업을 분리해 설계하는 것이 더 좋지 않을까? 라는 생각이 들었다. 프로젝트 크기에 비해 과도하게 구분하는 것 또한 좋지 않겠지만, 아래와 같이 한번 구조를 생각해봤다. 구조 예시 아 그리고 protocol과 enum을 코드에서 잘 사용하면 휴먼에러를 확 줄일 수 있는 것을 체감하였다. 그리고 enum을 통한 패턴 매칭이 정말 유용하다 Service / NetworkService protocol NetworkServiceType { func fetchData(completion: @escaping (NetworkResult<MovieResponse>) -> Void) } 프로토콜 타입 선언한 데이터 처리 프로토콜 타입을 채택함으로써 휴먼에러를 방지하고, NetworkResult를 제네릭하게 만들어놓은 것을 활용해 모델을 안에 부여한다. NetworkResult는 성공, 실패 여부

Swift Student Challenge 2024 [내부링크]

애플에서 주최하는 Swift Student Challenge에 참여하려 한다. https://developer.apple.com/swift-student-challenge/ Swift Student Challenge Showcase your love of coding by submitting your app playground to the Swift Student Challenge. developer.apple.com 대학교 졸업 상태라 학생신분이 아니지만 AppleDeveloper Academy 소속으로 참여가 가능하다고 한다. 참가시 숙지해야 할 사항이다. Requirements: Your submission must be an app playground (.swiftpm) in a ZIP file. Your creation should not rely on a network connection and any resources used in your app playground s

[ASD 1일차] 크레쉬 나는 이유? [내부링크]

지금 사용자가 입력한 자신의 정보(이름, 나이)를 저장하고, 이를 사용하고자 한다. 그래서 UserDefaults에 간단히 저장해서 이를 꺼내 사용하고자 하는데 생각할 부분 import Foundation import Combine class StartTestViewModel: ObservableObject { @Published var userInfo: UserInfo var subscriptions: Set<AnyCancellable> = [] init() { let defaultName = UserDefaults.standard.string(forKey: "name") ?? "Unknown Name" let defaultBirthDate = UserDefaults.standard.object(forKey: "birthDate") as? Date ?? Date() let defaultAge = UserDefaults.standard.integer(forKey: "age") use

CompositionalLayout + DiffableDataSource + Snapkit + Kingfisher [내부링크]

다양한 모양의 레이아웃 구현 순서 1. 컬렉션 뷰 cell UI - 등록 2. 레이아웃 구현 - 3가지 3. datasource -> cellProvider 4. snapshot -> datasource.apply(snapshot) 1~4번의 순서에 따라 차근차근 진행하면 원하는 모양의 구조를 손쉽게 잡을 수 있다. 섹션과 아이템 정의 컬렉션 뷰 섹션으로 들어가기 위해서는 hashable이라는 프로토콜을 채택해야 한다. 보통 서버API로 호출해서 받은 응답 값으로 컬렉션 뷰를 구현하는데 그 데이터들이 셀 안으로 들어간다. 그래서 해당 데이터들을 item안에 넣어 주어야 한다. Item.swift struct Section: Hashable { let id: String } enum Item: Hashable { case banner(homeItem) case normalCarousel(HomeItem) case listCarousel(HomeItem) } struct HomeItem

Generic Network 만들어보기 [내부링크]

제네릭을 사용하여 효율적인 네트워크 레이어를 구축 라이브러리: RxSwift와 RxAlamofire RxSwift: 반응형 프로그래밍을 위한 Swift 라이브러리로, 데이터 스트림을 관찰하고 반응하는 프로그래밍을 간결하고 이해하기 쉽게 만들어 줍니다. RxAlamofire: Alamofire의 기능을 RxSwift와 결합하여, HTTP 네트워크 요청을 더욱 강력하고 유연하게 만들어 줍니다. 네트워크 통신은 거의 모든 모바일 앱에서 필수적인 부분입니다. 하지만, 다양한 API와 다양한 데이터 타입을 처리하기 위해 많은 반복 코드를 작성해야 하는 문제가 있습니다. => 해결하기 위해 제네릭을 사용한 네트워크 레이어를 구축할 수 있습니다. import Foundation import RxSwift import RxAlamofire class Network<T:Decodable> { private let endpoint: String private let queue: ConcurrentDi

decoder.container(keyedBy:) [내부링크]

Json데이터를 Swift 구조체나 클래스로 디코딩하는데 사용되는 Decodable 프로토콜의 핵심 부분이다. Decodable 프로토콜 Decodable은 타입들이 JSON과 같은 데이터를 해당 타입으로 역직렬화(디코딩)하기 위해 채택하는 프로토콜입니다. Decoder Decoder 인스턴스는 Decodable 타입의 init(from:) 초기화자에 제공됩니다. 이는 디코딩되고 있는 데이터를 나타내며, 데이터의 타입에 맞는 방식으로 값을 검색하는 메서드를 제공합니다. 키 기반 디코딩 컨테이너 디코딩 컨테이너는 디코더에 의해 보유된 데이터에 접근할 수 있게 해줍니다. keyedBy: 메서드는 지정된 키 타입과 일치하는 컨테이너를 디코더로부터 요청합니다. 코드에서는 CodingKeys가 키 타입으로 사용되며, 이는 CodingKey 프로토콜을 준수해야 합니다. import Foundation struct TVListModel: Decodable { let page: Int let re

Get, Post URLSession으로 보내기 [내부링크]

오늘은 다른 라이브러리를 사용하지 않고 URLSession만으로 Get, Post를 해보는 연습을 했다. 라이브러리를 통해 쉽게 구현할 수 있지만 사용하지 않고 구현하지 못하면 의미가 없다는 생각이 들었다. 엔드포인트는 이전에 compositionalLayout 연습할 때 사용한 영화 API를 사용해보겠다. 제일 처음으로 데이터 구조를 짜보자. import Foundation struct MovieResponse: Codable { var page: Int var results: [Movie] } struct Movie: Codable { var adult: Bool var backdropPath: String var genreIds: [Int] var id: Int var originalLanguage: String var originalTitle: String var overview: String var popularity: Double var posterPath: String

UIKit Code Base SceneDelegate 설정 [내부링크]

import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) window?.rootViewController = ViewController() window?.makeKeyAndVisible() } }

[Swfit: 완전탐색] 체스판 다시 만들기 1018 [내부링크]

완전 탐색을 통해 체스판을 정해진 패턴에 맡게 만드는 문제이다. 가장 먼저 체스판을 8*8 사이즈로 몇개 자를 수 있는지? 그 가능한 횟수 안에서 다시 완전 탐색을 통해 WB를 칠하는 횟 수를 더해서 출력한다. 체스판 다시 칠하기 성공 시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율 2 초 128 MB 111584 55303 44241 49.764% 문제 지민이는 자신의 저택에서 MN개의 단위 정사각형으로 나누어져 있는 M×N 크기의 보드를 찾았다. 어떤 정사각형은 검은색으로 칠해져 있고, 나머지는 흰색으로 칠해져 있다. 지민이는 이 보드를 잘라서 8×8 크기의 체스판으로 만들려고 한다. 체스판은 검은색과 흰색이 번갈아서 칠해져 있어야 한다. 구체적으로, 각 칸이 검은색과 흰색 중 하나로 색칠되어 있고, 변을 공유하는 두 개의 사각형은 다른 색으로 칠해져 있어야 한다. 따라서 이 정의를 따르면 체스판을 색칠하는 경우는 두 가지뿐이다. 하나는 맨 왼쪽 위 칸이 흰색인 경우, 하

[Swift: 정렬] 단어 정렬 1181 [내부링크]

단어 정렬 성공 시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율 2 초 256 MB 168495 70541 52889 40.354% 문제 알파벳 소문자로 이루어진 N개의 단어가 들어오면 아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오. 길이가 짧은 것부터 길이가 같으면 사전 순으로 단, 중복된 단어는 하나만 남기고 제거해야 한다. 입력 첫째 줄에 단어의 개수 N이 주어진다. (1 ≤ N ≤ 20,000) 둘째 줄부터 N개의 줄에 걸쳐 알파벳 소문자로 이루어진 단어가 한 줄에 하나씩 주어진다. 주어지는 문자열의 길이는 50을 넘지 않는다. 출력 조건에 따라 정렬하여 단어들을 출력한다. 예제 입력 1 13 but i wont hesitate no more no more it cannot wait im yours 예제 출력 1 i im it no but more wait wont yours cannot hesitate for 문으로 중복 제거했더니 시간초과 실패가 떴다. 그

FlexLayout, PinLayout [내부링크]

많은 공고에서 FlexLayout과 PinLayout을 볼 수 있다. 어떤 라이브러리일까? 궁금해서 한번 사용해보고자 한다. snapKit을 처음 사용할 때 오토레이아웃을 보다 짧은 코드로 쉽게 설정할 수 있어서 획기적이라고 생각했는데, FlexLayout과 PinLayout은 어떨지 기대된다. cocoapod로 라이브러리를 설정하는 과정은 생략~ https://github.com/layoutBox/FlexLayout GitHub - layoutBox/FlexLayout: FlexLayout adds a nice Swift interface to the highly optimized facebook/yoga flexbox implementation. Concise, intuitive & chainable syntax. FlexLayout adds a nice Swift interface to the highly optimized facebook/yoga flexbox implemen

카카오 로그인 구현 [내부링크]

국민 앱인 카카오 로그인을 구현해 보겠습니다~ 카카오 로그인 시 액세스 토큰과 리프레쉬 토큰 등을 기본으로 제공해 줍니다. Kakao Developers에서 설정을 해야 합니다. 추가된 애플리케이션 클릭 후 본인에게 맞는 플랫폼 설정하기~ + 여기서 번들ID를 넣어주자. (번들 ID는 아래 이미지와 같이 확인할 수 있다. 카카오 로그인 활성화 ON으로 만들고~ 동의 항목 설정해준다. 이제 필요한 라이브러리를 다운 받아보자 pod file에 아래와 같이 작성 후 pod install 이후 info.plist를 소스코드로 열고 아래 코드를 붙여넣는다. <key>LSApplicationQueriesSchemes</key> <array> <!-- 카카오톡으로 로그인 --> <string>kakaokompassauth</string> <!-- 카카오링크 --> <string>kakaolink</string> </array> info에서 URL Types를 클릭 URL Schemes에 항목에

Class와 Struct [내부링크]

공통점 1. 프로퍼티, 메서드를 사용가능 2. init()사용 가능 3. extension, Protocol 사용가능 차이점 Struct는 자동으로 init을 생성해주고 Class는 자동으로 생성해주지 않는다. class만 상속이 가능하다. struct는 상속이 불가능하다. 변수 할당에는 struct는 값의 복사 후 지정 class는 똑같은 값을 지정한다. ( struct는 값타입, class는 참조 타입) => class는 하나바뀌면 영향받아서 같이 바뀜, struct는 독립적?으로 값을 갖고있음 영향을 안받음 값 타입 vs 참조타입 어느 방식으로 메모리에 젖아되고 메모리에 저장된 객체가 어떻게 쓰이는가? 값 타입: 내용이 같지만 값이 복사되어 메모리에 들어간다. -> 변수1이 변해도 변수2에 영향을 미치지 않는다. 참조 타입: 메모리 주소를 복사한다. -> 변수1이 변하면 변수 2에 영향을 미친다. Heap(참조)/Stack(값) Heap영역엔 참조타입이 (즉, class) 사용

ARC(Auto Reference Count)/ 순환참조/ 강한 참조, 약한 참조 [내부링크]

지워져야 할 class가 메모리에 계속 남아 있어 비용이 계속 드는 것을 메모리 누수, Memory Leak이라고 한다. 메모리에 class가 누적되는 것을 예방해주는 것이 ARC다. 자동으로 swift에서 참조 값이 늘어나면 count가 올라가고(retain), 참조 count가 0이 되면 메모리에서 제거된다. 자동으로 해주는데 우리가 왜 신경을 써야할까? -> 변수를 지우면서 참조가 감소해도 참조가 0이 되지 않는 경우들이 있다. : 순환참조 두 객체가 서로를 참조하고 있어 참조가 계속 증가한다. 순환참조로 인해 reference count가 0이 되지 않는 모습, 이를 확인할 수 있는데 CFGetRetainCount()를 사용하면 count 값이 몇인지 볼 수 있다. class ClassOne { var reference: ClassTwo? } class ClassTwo { var reference: ClassOne? } // reference count var class1 =

Dispatch [내부링크]

정적 디스패치: 컴파일 타임에 결정 만약 struct라면 상속이 되지 않기 때문에 struct안에 있는 메소드를 실행하는 작업이 정적 디스패치이다. 동적 디스패치에 비해 빠르다. 동적 디스패치: 런타임에 결정된다. class라 상속이 되어 있어 어떤 메소드를 실행해야 될지 모르기 때문에 런타임에 실제로 결정되는 작업이 동적 디스패치이다. 정적 디스패치에 비해 느리다. 그래서 struct를 사용하는 것이 권장되긴 하나, 객체 지향적 코드를 작성하기 위해 class를 사용할 수 있기 때문에 class를 사용하지 않을 수 없다. 중복된 코드를 제거하는 등의 장점이 있기 때문이다. 여기서 final을 붙이면 class에서도 정적 디스패치를 사용한다. final을 붙이면 상속이 불가함을 선언하는 것이다.

스레드, 데드락/GCD / DispatchQueue [내부링크]

main Thread는 직렬로 실행된다 -> 작업이 하나씩 돌아감. 속도가 느려질 수 밖에 없다. 연속적인 작업을 수행할 경우 동기 작업을 한다. DispatchQueue.main.sync{ // 해당 작업을 직렬로 처리 // 동기 처리 } DispatchQueue.main.async{ // 비동기 처리 } main이 아닌 다른 Thread 병렬 Thread는 작업의 속도가 빠르다. 한번에 여러 작업이 처리 DispatchQueue.global().sync{ // 동기 } DispatchQueue.global().async{ // 비동기 } DispatchQueue.global(qos: .userInteractive).async { // 우선순위 지정 } Dispatch 우선순위도(상위일수록 중요도 증가) main Thread는 가장 먼저 실행되고 UI를 담당한다. DispatchQueue.main.async { setUI(result) } 다른 서브스레드들은 작업을 하고 있는지 관

클로저, 캡처링 [내부링크]

클로저는 이름없는 함수이며 참조타입이다. 즉, 메모리 Heap에 저장되고 메모리 카운트를 통해 메모리에 저장된다. 레퍼런스 캡처링 기본적으로 사용할 변수 값을 참조해 원본 값이 변경되면 영향을 받는 레퍼런스 캡처링을 사용하게 된다. 생성 이후의 값에 영향을 받음 var a = 0 var b = 0 let closure = { print(a, b) // 레퍼런스 캡처링 } a = 5 closure() // 실행값 5 0 밸류 캡처링 캡쳐 리스트를 사용하면 밸류 캡쳐링을 하게되어 클로저 생성 당시의 값을 갖고 있다가 사용하게 된다. 생성 이후의 값에 영향이 없음 var a = 0 var b = 0 let clouser = { [a,b] in // 밸류 캡처링, 캡쳐 리스트 print(a,b) } a = 5 closure() // 실행값 0,0 그렇지만 class의 경우 밸류 캡처링 방법을 사용해도 되지 않고 레퍼런스 캡처링이 실행된다. class TestClass { public var

[Swift: 깊이/너비 우선 탐색(DFS/BFS)] 네트워크 [내부링크]

네트워크 darklight sublimevimemacs 문제 설명 네트워크란 컴퓨터 상호 간에 정보를 교환할 수 있도록 연결된 형태를 의미합니다. 예를 들어, 컴퓨터 A와 컴퓨터 B가 직접적으로 연결되어있고, 컴퓨터 B와 컴퓨터 C가 직접적으로 연결되어 있을 때 컴퓨터 A와 컴퓨터 C도 간접적으로 연결되어 정보를 교환할 수 있습니다. 따라서 컴퓨터 A, B, C는 모두 같은 네트워크 상에 있다고 할 수 있습니다. 컴퓨터의 개수 n, 연결에 대한 정보가 담긴 2차원 배열 computers가 매개변수로 주어질 때, 네트워크의 개수를 return 하도록 solution 함수를 작성하시오. 제한사항 컴퓨터의 개수 n은 1 이상 200 이하인 자연수입니다. 각 컴퓨터는 0부터 n-1인 정수로 표현합니다. i번 컴퓨터와 j번 컴퓨터가 연결되어 있으면 computers[i][j]를 1로 표현합니다. computer[i][i]는 항상 1입니다. 입출력 예 n computers return 3 [[

[GDF 17일차] 플로깅 기능(Map, PolyLine), 사당 -&gt; 신촌 테스트 [내부링크]

오늘은 조깅과 쓰레기 줍는 행위가 합쳐진 플로깅 기능을 만들어 볼거다. 기능 구현을 위해 필요하다고 생각하는 것 정리. 지도 받아오기 사용자 위치에 따른 위치 받기 사용자 이동경로 표시 사용자가 이동한 거리, 속도, 시간 지도받아오기 지도를 불러오는건 그렇게 어렵지 않았다. MapKit을 import하는 것만으로 거의 해결되었다고 볼 수 있는데. // 지도 뷰 let map: MKMapView = { let map = MKMapView() map.overrideUserInterfaceStyle = .light map.translatesAutoresizingMaskIntoConstraints = false // 사용자의 현재 위치 표시 map.showsUserLocation = true // 유저의 위치를 추적 map.setUserTrackingMode(.followWithHeading, animated: true) return map }() CLLocationManager.deleg

[GDF 18일차] 상점(모달창 기반) [내부링크]

상점을 만들려고 한다. 챌린지를 통해 얻은 재화로 캐릭터를 꾸밀 수 있게 하기 위함인데 상점이 생각 보다 복잡하다. 우선 첫번째로 배경 홈화면에서 클릭시 모달창으로 나타나야한다. 그리고 위에 아이템의 부위별 탭바가 존재하고 이를 스크롤 뷰로 만들어야한다. 제일 고민인건 어떻게 상점의 아이템들을 눌렀을 때 유저의 캐릭터에 입혀주냐이다... 일단 레이아웃을 먼저 짜보자... 모달창 형태로 만들기 위해 HomeVC에서 아이콘 클릭시 modal형태로 표출되게 컨테이너 박스를 만들었다. modalPresentationStyle: 모달 뷰가 어떻게 표시될지를 결정합니다. - .overFullScreen을 사용하면 모달이 활성화되어 있는 동안에도 이전 뷰 컨트롤러의 상태를 그대로 유지할 수 있습니다. 예를 들어, 비디오 플레이어가 재생 중인 상태에서 새로운 설정 화면을 모달로 띄웠을 때, 비디오는 멈추지 않고 계속 재생됩니다. - .fullScreen: 모달 뷰가 활성 뷰 컨트롤러를 완전히 덮습

[Swift] 백준 입력값 받기 [내부링크]

결론: 입력된 한 줄을 읽고 정수 배열로 반환 readLine() -> String? 반환, 강제 언래핑 필요. split() -> 주어진 구분자에 따라 배열을 반환 여기선 " "(공백) + [substring]요소로 반환 이런 substring 요소들은 다른 타입으로 변환되어 사용된다. map { Int($0)!}을 사용해 Substring을 Int로 변환해 사용. + Int생성자는 옵셔널을 발생하기 때문에 강제 언래핑을 해야함. let input = readLine()!.split(separator: " ").map { Int($0)! } print(input)

[Swift: 깊이/너비 우선 탐색(DFS/BFS)] 1260번 - DFS와 BFS [내부링크]

let inputs = readLine()!.split(separator: " ").map(){Int(String($0))!} let n = inputs[0] let m = inputs[1] let v = inputs[2] var graph = [[Int]](repeating: [], count: n) graph.append([]) for _ in 0..<m { let arr = readLine()!.split(separator: " ").map(){Int(String($0))!} graph[arr[0]].append(arr[1]) graph[arr[0]] = graph[arr[0]].sorted(by: <) graph[arr[1]].append(arr[0]) graph[arr[1]] = graph[arr[1]].sorted(by: <) } var visited = [Bool](repeating: false, count: n+1) func dfs(_ start: Int) { visi

[Swift] Stack [내부링크]

import Foundation struct Stack { var stack: [Int] = [] mutating func push(x: Int) { stack.append(x) } mutating func pop() -> Int { return stack.isEmpty ? -1 : stack.removeLast() } func size() -> Int { return stack.count } func empty() -> Int { return stack.isEmpty ? 1 : 0 } func top() -> Int { return stack.last ?? -1 } } let n = Int(readLine()!)! var stack = Stack() for _ in 0..<n { let line = readLine()!.split(separator: " ") switch line[0] { case "push" : stack.push(x: Int(line[1])!) case "pop

[GDF 19일차] 상점 UI [내부링크]

18일에 이어 상점 UI를 만들어야 한다. 근데 카테고리 탭바가 있고 이 탭바가 가로 스크롤로 넘기면서 볼 수 있게 만들어야한다. 어떻게 하지? 음.... 왼쪽이 피그마로 미리 구현한 완성된 상점의 모습인데.. 버튼 제목 배열 수 만큼 반복문을 통해 버튼을 만들고 그 버튼들을 항목이 들어갈 박스에 넣었더니... 레이아웃이 엉망이다... 수정해보자 우선 버튼에 대해 정의 후 lazy var storeTapBtn: [UIButton] = { let storeItemTap: [String] = ["Hair", "Top", "Pants", "Shoes", "Acc"] var storeBtn = [UIButton]() storeItemTap.forEach { let btn = UIButton() btn.setTitle($0, for: .normal) btn.setTitleColor(.black, for: .normal) btn.translatesAutoresizingMaskIntoConstr

[GDF 20일차] 드디어 스크롤 된다.. + UICollectionViewFlowLayout [내부링크]

사촌 여동생 결혼식으로 서울에서 안동까지... 오랜만에 본가에 다녀와서 좋았지만, 예상보다 일정 소비를 너무 많이 했다. 그동안 프로젝트 일정 보다 조금 빠르게 해둬서 다행이다... 자! 다시 열심히 해보자 상점에서 스크롤이 안되고 있었는데, 이제 스크롤이 된다. 하루를 종일 이유를 찾아 다녔는데 설마 설마? 하는 마음에 탭바 부분의 가장 최상단 뷰에 isUserInteractionEnabled = true를 했더니 해결되었다..... 하.. 역시 기본부터 차근차근 해결해나가는게 중요하다. 음.. 근데 스크롤 막대기를 꾸미고 싶은데, 찾아보니 커스텀으로 만들면 된다는데, 그다지 추천하지 않는다고 한다. 우선 밑에 급한 기능들 부터 마무리하고 후에 커스텀하게 만들어 보자. 버튼을 클릭했을 때 원하는 클릭 이미지가 있는데 그 액션을 넣을 때 sender를 활용했다. 그리곤 눌린 버튼이 아닐 경우 이미지를 다시 원래대로. @objc func storeTapped(sender: UIButt

[Swift: 그리드] 2839번 설탕 [내부링크]

설탕 배달 성공다국어 시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율 1 초 128 MB 311678 116253 87289 36.904% 문제 상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다. 상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다. 상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000) 출력 상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면

CocoaPods, RxSwift 설치 [내부링크]

CocoaPods를 이용해 RxSwift를 설치해보겠습니다. 우선 CocoaPods를 설치해야 합니다. sudo gem install cocoapods 근데 이 과정에서 ruby와 gem의 버전 호환성 문제가 발생했습니다. 젬이 Ruby 2.7.0이상을 필요로 하는데 저는 2.6.10으로 충돌 Ruby를 업데이트 합시다 brew install ruby PATH 업데이트: 설치 후, Homebrew Ruby 경로를 셸 구성 파일에 추가해야 합니다. 시스템이 새로 설치한 Ruby 버전을 기본 시스템 Ruby 대신 사용하도록 하는 중요한 단계입니다. 구성 파일 열기 터미널에서 다음 명령어 중 하나를 사용할 수 있습니다: Bash의 경우: open -e ~/.bash_profile Zsh의 경우: open -e ~/.zshrc Homebrew Ruby 경로 확인 : 먼저, Homebrew를 통해 설치된 Ruby의 정확한 경로를 확인합니다. 터미널에서 다음 명령어를 실행하세요 brew --p

RxSwift(feat: 순환참조, URLSession, Operator, Combining, Subject, Rxcocoa) [내부링크]

RxSwift에 대해 공부해봅시다. 한번에 이해되기 어렵기 때문에 반복 숙달을 통해 익숙해 지는게 중요할 것 같습니다. 핵심 개념 RxSwift는 비동기적으로 생기는 데이터를 Completion같은 클로저를 통해서 전달하는 것이 아닌 return 값으로 전달하기 위한 것이다. RxSwift의 익혀야 할 핵심 1. 비동기로 생기는 데이터를 Observable로 감싸서 리턴하는 방법 2. Observable로 오는 데이터를 받아서 처리하는 방법. 3. 취소되었을 때 해야하는 행동은 observable를 create해서 return하는 곳에 적어두면 된다. 4.Observable의 생명주기 4-1. Create 4-2. Subscribe 4-3. onNext ---- 끝 ---- 4-4. onCompleted / onError 4-5. Disposed 5. 만들어진 observable은 한 번 subscribe에 의해 동작이 시작되면 complete, error, dispose에 의해서

malloc scribble, malloc stack 메모리 누수 검사 [내부링크]

Malloc Scribble malloc scribble을 활성화하면, 해제된 객체의 메모리가 미리 정의된 값(0x55)으로 채워집니다. 이는 코드가 이미 해제된 메모리에 접근하는 것을 신속하게 식별하는 데 도움이 됩니다. 사용 방법: 이 기능은 메모리를 무효화하는 버그를 탐지하는 데 특히 유용합니다. 메모리 블록이 해제되면 무효한 값으로 덮어씌워지며, 이를 실행하면 예외가 발생합니다. 이를 통해 해제된 메모리 블록에 남아 있는 포인터를 쉽게 식별하고 수정할 수 있습니다. Malloc Stack 활성화되면, malloc stack 로깅은 Xcode가 할당의 백트레이스를 구축하는 데 도움을 줍니다. 이는 객체가 어디에서 참조되는지 이해하는 데 유용합니다. 사용 방법: 이 기능은 복잡한 애플리케이션에서 메모리 누수의 정확한 위치를 파악하기 어려울 때 유용합니다. 각 메모리 할당 시점의 함수 호출 스택을 기록합니다. 설정하고 재실행 후 그래프 디버깅 바로 간다. (동그라미 3개 연결되어있

[Swift] 아이스 아메리카노 [내부링크]

아이스 아메리카노 문제 설명 머쓱이는 추운 날에도 아이스 아메리카노만 마십니다. 아이스 아메리카노는 한잔에 5,500원입니다. 머쓱이가 가지고 있는 돈 money가 매개변수로 주어질 때, 머쓱이가 최대로 마실 수 있는 아메리카노의 잔 수와 남는 돈을 순서대로 담은 배열을 return 하도록 solution 함수를 완성해보세요. 제한사항 0 < money ≤ 1,000,000 입출력 예 money result 5,500 [1, 0] 15,000 [2, 4000] import Foundation func solution(_ money:Int) -> [Int] { var result:[Int] = [] var coffe = money / 5500 var changes = money % 5500 result.append(coffe) result.append(changes) return result }

[Swift] 중복된 숫자 개수 [내부링크]

중복된 숫자 개수 문제 설명 정수가 담긴 배열 array와 정수 n이 매개변수로 주어질 때, array에 n이 몇 개 있는 지를 return 하도록 solution 함수를 완성해보세요. 제한사항 1 ≤ array의 길이 ≤ 100 0 ≤ array의 원소 ≤ 1,000 0 ≤ n ≤ 1,000 입출력 예 array n result [1, 1, 2, 3, 4, 5] 1 2 [0, 2, 3, 4] 1 0 import Foundation func solution(_ array:[Int], _ n:Int) -> Int { var a = array.filter{$0 == n} return a.count }

머쓱이보다 키 큰 사람 [내부링크]

문제 설명 머쓱이는 학교에서 키 순으로 줄을 설 때 몇 번째로 서야 하는지 궁금해졌습니다. 머쓱이네 반 친구들의 키가 담긴 정수 배열 array와 머쓱이의 키 height가 매개변수로 주어질 때, 머쓱이보다 키 큰 사람 수를 return 하도록 solution 함수를 완성해보세요. 제한사항 1 ≤ array의 길이 ≤ 100 1 ≤ height ≤ 200 1 ≤ array의 원소 ≤ 200 입출력 예 array height result [149, 180, 192, 170] 167 3 [180, 120, 140] 190 0 import Foundation func solution(_ array:[Int], _ height:Int) -> Int { var a = array.filter{$0 > height}.count return a }

[Swift] 문자열안에 문자열 [내부링크]

문제 설명 문자열 str1, str2가 매개변수로 주어집니다. str1 안에 str2가 있다면 1을 없다면 2를 return하도록 solution 함수를 완성해주세요. 제한사항 1 ≤ str1의 길이 ≤ 100 1 ≤ str2의 길이 ≤ 100 문자열은 알파벳 대문자, 소문자, 숫자로 구성되어 있습니다. 입출력 예 str1 str2 result "ab6CDE443fgh22iJKlmn1o" "6CD" 1 "ppprrrogrammers" "pppp" 2 "AbcAbcA" "AAA" 2 import Foundation func solution(_ str1:String, _ str2:String) -> Int { return str1.contains(str2) ? 1 : 2 }

[Swift] 피자 나눠 먹기 (1) [내부링크]

피자 나눠 먹기 (1) 문제 설명 머쓱이네 피자가게는 피자를 일곱 조각으로 잘라 줍니다. 피자를 나눠먹을 사람의 수 n이 주어질 때, 모든 사람이 피자를 한 조각 이상 먹기 위해 필요한 피자의 수를 return 하는 solution 함수를 완성해보세요. 제한사항 1 ≤ n ≤ 100 입출력 예 n result 7 1 1 1 15 3 import Foundation func solution(_ n:Int) -> Int { return Int(ceil(Double(n)/7)) }

[Swift] 중앙값 구하기 [내부링크]

중앙값 구하기 문제 설명 중앙값은 어떤 주어진 값들을 크기의 순서대로 정렬했을 때 가장 중앙에 위치하는 값을 의미합니다. 예를 들어 1, 2, 7, 10, 11의 중앙값은 7입니다. 정수 배열 array가 매개변수로 주어질 때, 중앙값을 return 하도록 solution 함수를 완성해보세요. 제한사항 array의 길이는 홀수입니다. 0 < array의 길이 < 100 -1,000 < array의 원소 < 1,000 입출력 예 array result [1, 2, 7, 10, 11] 7 [9, -1, 0] 0 import Foundation func solution(_ array:[Int]) -> Int { var a = array.count/2 var b = array.sorted() return b[a] } sorted()를 통해 배열을 정렬했다. sorted()는 기본 값이 오름차순이다. 내림차순은 어떻게 만들까? array.sorted(by: >) 이렇게하면 내림차순으로 정렬된

[GDF 13일차] 싱글톤 패턴을 활용한 CustomTabBarViewController의 전역 접근 방법 [내부링크]

Custom TabBar UIViewController를 사용해 커스텀 탭바를 만들었다. 기존의 UITabBarController를 통해 만들었던 메인 탭바는 원하는대로 변경하는데 한계가 분명했기 때문이다. 커스텀 탭바를 구성하고 홈 페이지에서 아이콘을 클릭해 다음 화면으로 넘어갈 때 탭바가 사라지게 해야되는데, 기존의 단순 .isHidden = true로는 탭바가 사라지지 않았다. 어떻게 하면 커스텀 탭바에 접근해 .isHidden이 사용되게 할 수 있을까 생각하다. 싱글톤 패턴으로 class CustomTabBarViewController: UIViewController, CustomTabBarDelegate { static var shared: CustomTabBarViewController! // .... override func viewDidLoad() { super.viewDidLoad() CustomTabBarViewController.shared = self // ..

[Swift: 완전탐색] 최소직사각형 [내부링크]

최소직사각형 문제 설명 명함 지갑을 만드는 회사에서 지갑의 크기를 정하려고 합니다. 다양한 모양과 크기의 명함들을 모두 수납할 수 있으면서, 작아서 들고 다니기 편한 지갑을 만들어야 합니다. 이러한 요건을 만족하는 지갑을 만들기 위해 디자인팀은 모든 명함의 가로 길이와 세로 길이를 조사했습니다. 아래 표는 4가지 명함의 가로 길이와 세로 길이를 나타냅니다. 명함 번호 가로 길이 세로 길이 1 60 50 2 30 70 3 60 30 4 80 40 가장 긴 가로 길이와 세로 길이가 각각 80, 70이기 때문에 80(가로) x 70(세로) 크기의 지갑을 만들면 모든 명함들을 수납할 수 있습니다. 하지만 2번 명함을 가로로 눕혀 수납한다면 80(가로) x 50(세로) 크기의 지갑으로 모든 명함들을 수납할 수 있습니다. 이때의 지갑 크기는 4000(=80 x 50)입니다. 모든 명함의 가로 길이와 세로 길이를 나타내는 2차원 배열 sizes가 매개변수로 주어집니다. 모든 명함을 수납할 수 있

[Swift: 완전탐색] 모의고사 [내부링크]

모의고사 문제 설명 수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다. 1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ... 2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ... 3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ... 1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요. 제한 조건 시험은 최대 10,000 문제로 구성되어있습니다. 문제의 정답은 1, 2, 3, 4, 5중 하나입니다. 가장 높은 점수를 받은 사람이 여럿일 경우, r

[Swift: 그리디] 체육복 [내부링크]

체육복 문제 설명 점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다. 전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요. 제한사항 전체 학생의 수는 2명 이상 30명 이하입니다. 체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다. 여벌의 체육복을 가져

[GDF 14일차] Table 연습 [내부링크]

챌린지 문제를 만들기 위해 테이블을 만들어보자. UITableViewController를 사용할지, UICollectionView를 사용할지 고민이다. 세로로 구성된 셀이기 때문에 단순하게 UITableView를 사용하는게 편리할 거 같은데 다양한 레이아웃을 구성할 수 있는 UICollectionView도 있다는 것을 발견했다. 정리내용 1. 레이아웃 및 구조의 차이: UITableView: 단일 섹션 또는 다중 섹션의 세로 스크롤 목록을 표시합니다. 주로 리스트 형태의 데이터를 표시하는 데 사용됩니다. UICollectionView: 다양한 레이아웃 및 그리드를 사용하여 여러 아이템을 표시합니다. 다양한 레이아웃을 통해 복잡한 그리드 및 다중 섹션 레이아웃을 구현할 수 있습니다. 2. 데이터 표시 방식: UITableView: 주로 단일 열의 데이터를 표시합니다. 각 셀은 수직으로 쌓여 있습니다. UICollectionView: 여러 열 및 행의 데이터를 표시할 수 있습니다. 다양

[Swift: 정렬] 가장 큰 수 [내부링크]

가장 큰 수 문제 설명 0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요. 예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 수는 6210입니다. 0 또는 양의 정수가 담긴 배열 numbers가 매개변수로 주어질 때, 순서를 재배치하여 만들 수 있는 가장 큰 수를 문자열로 바꾸어 return 하도록 solution 함수를 작성해주세요. 제한 사항 numbers의 길이는 1 이상 100,000 이하입니다. numbers의 원소는 0 이상 1,000 이하입니다. 정답이 너무 클 수 있으니 문자열로 바꾸어 return 합니다. 입출력 예 numbers return [6, 10, 2] "6210" [3, 30, 34, 5, 9] "9534330" import Foundation func solution(_ numbers:[Int]) -> Strin

[GDF 15일차] Table 완성, Camera접근 [내부링크]

Table을 구현했다. TableCell을 만들었고 TableViewController가 아닌 커스텀하게 만들고 싶어 UIViewController Table delegate 활용 // 섹션에 표시할 셀의 개수 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 } // 섹션 수 func numberOfSections(in tableView: UITableView) -> Int { return challengeVM.numberOfChallenges } // 행에 대한 셀을 반환 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cha

[GDF 16일차] 사진 찍고 갤러리 저장, 팝업, 라이트 활성화 [내부링크]

카메라를 활성화 하는데 까진 성공했다. 사진 기능 추가해야 되는 것 1. 사진을 찍기 2. 찍은 사진에 대한 처리를 해줘야 한다.( 갤러리에 저장 + 모달창에 띄워 유저가 확인할 수 있도록) 3. 라이트 활성화 Previous image Next image 사진 촬영 후 모달창 표시 + 갤러리 저장 // 라이트 활성화 사용자 휴대폰 갤러리에 찍은 사진을 저장하기 위해서 아래와 같이 설정해야된다. info.plist <key>NSPhotoLibraryAddUsageDescription</key> <string>앱에서 찍은 사진을 앨범에 저장하기 위해 사용합니다.</string> 사진 저장 // AVCapturePhotoCaptureDelegate 프로토콜 일부, 카메라가 사진 찍고 자동 호출 -> 찍힌 사진 처리하는 로직임 func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCaptureP

[Swift] 문자열 뒤집기 [내부링크]

간단히 문자를 뒤집는 문제이다. reversed()를 사용하면 되는데 이때 String으로 변환을 해주어야 한다. 왜냐면 reversed()를 했을 때 문제가 틀렸다고 나와 type(of:)로 확인해 봤는데 ReversedCollection<String>이 나왔다. print(type(of:my_string.reversed())) // ReversedCollection<String> 문자열 뒤집기 문제 설명 문자열 my_string이 매개변수로 주어집니다. my_string을 거꾸로 뒤집은 문자열을 return하도록 solution 함수를 완성해주세요. 제한사항 1 ≤ my_string의 길이 ≤ 1,000 입출력 예 my_string return "jaron" "noraj" "bread" "daerb" import Foundation func solution(_ my_string:String) -> String { return String(my_string.reversed()) }

[Swift] 배열 뒤집기 [내부링크]

배열 뒤집기 문제 설명 정수가 들어 있는 배열 num_list가 매개변수로 주어집니다. num_list의 원소의 순서를 거꾸로 뒤집은 배열을 return하도록 solution 함수를 완성해주세요. 제한사항 1 ≤ num_list의 길이 ≤ 1,000 0 ≤ num_list의 원소 ≤ 1,000 입출력 예 num_list result [1, 2, 3, 4, 5] [5, 4, 3, 2, 1] [1, 1, 1, 1, 1, 2] [2, 1, 1, 1, 1, 1] [1, 0, 1, 1, 1, 3, 5] [5, 3, 1, 1, 1, 0, 1] reversed()를 호출하면 역순으로 된 ReversedCollection이 반환되지만, 이를 배열로 변환하지 않으면 실제로 역순 정렬된 배열을 얻을 수 없기 때문에 배열로 한번 더 받아야 한다. var a = num_list.map{String($0)}.reversed() var rA = Array(a) // ["5","4","3","2","1"] 그

[Swift] 5명씩 [내부링크]

5명씩 문제 설명 최대 5명씩 탑승가능한 놀이기구를 타기 위해 줄을 서있는 사람들의 이름이 담긴 문자열 리스트 names가 주어질 때, 앞에서 부터 5명씩 묶은 그룹의 가장 앞에 서있는 사람들의 이름을 담은 리스트를 return하도록 solution 함수를 완성해주세요. 마지막 그룹이 5명이 되지 않더라도 가장 앞에 있는 사람의 이름을 포함합니다. 제한사항 5 ≤ names의 길이 ≤ 30 1 ≤ names의 원소의 길이 ≤ 10 names의 원소는 영어 알파벳 소문자로만 이루어져 있습니다. 입출력 예 names result ["nami", "ahri", "jayce", "garen", "ivern", "vex", "jinx"] ["nami", "vex"] import Foundation func solution(_ names:[String]) -> [String] { // 5명씩, 놀이기구 줄 명단 -> names // names의 가장 앞 인덱스 이름 출력 // 5명이 안되도 가

[Swift] 할 일 목록 [내부링크]

할 일 목록 문제 설명 오늘 해야 할 일이 담긴 문자열 배열 todo_list와 각각의 일을 지금 마쳤는지를 나타내는 boolean 배열 finished가 매개변수로 주어질 때, todo_list에서 아직 마치지 못한 일들을 순서대로 담은 문자열 배열을 return 하는 solution 함수를 작성해 주세요. 제한사항 1 ≤ todo_list의 길이 1 ≤ 100 2 ≤ todo_list의 원소의 길이 ≤ 20 todo_list의 원소는 영소문자로만 이루어져 있습니다. todo_list의 원소는 모두 서로 다릅니다. finished[i]는 true 또는 false이고 true는 todo_list[i]를 마쳤음을, false는 아직 마치지 못했음을 나타냅니다. 아직 마치지 못한 일이 적어도 하나 있습니다. 입출력 예 todo_list finished result ["problemsolving", "practiceguitar", "swim", "studygraph"] [true, fal

[Swift] 짝수 홀수 개수 [내부링크]

짝수 홀수 개수 문제 설명 정수가 담긴 리스트 num_list가 주어질 때, num_list의 원소 중 짝수와 홀수의 개수를 담은 배열을 return 하도록 solution 함수를 완성해보세요. 제한사항 1 ≤ num_list의 길이 ≤ 100 0 ≤ num_list의 원소 ≤ 1,000 입출력 예 num_list result [1, 2, 3, 4, 5] [2, 3] [1, 3, 5, 7] [0, 4] import Foundation func solution(_ num_list:[Int]) -> [Int] { var result:[Int] = [] let a = num_list.enumerated().filter{$0.element % 2 == 0}.map{$0.element} let b = num_list.enumerated().filter{$0.element % 2 != 0}.map{$0.element} result.append(a.count) result.append(b.cou

[GDF 4일]MVVM, Operator, URLSession(configuration:), Error처리, Githu 임시 이미지 저장소 [내부링크]

3일차에 만든 Imagefetch()코드를 ViewModel에 옮기고 싶다. Util폴더에 ImageFetch 로직을 짜고 Home폴더에 HomeViewController의 서버와 통신하는 부분을 HomeViewModel로 분리했다. 1. ImageFetch.swift import Combine import UIKit final class ImageFetch { let session: URLSession init(configuration: URLSessionConfiguration) { session = URLSession(configuration: configuration) } func imageFetch(url: String) -> AnyPublisher<UIImage, Error>{ guard let imageURL = URL(string: url) else { return Fail(error: NetworkError.invalidURL).eraseToAnyPublisher()

[GDF 5일] UITapGestureRecognizer, AutoLayout [내부링크]

이미지를 요청하는데 이미지 하나당 한번의 요청이 들어가는게 비효율적인거 같다. 지금 몬스터, 캐릭터, 필드를 요청받는데 let imageURL = [ "https://github.com/leewanjae/imageAPI_Test/blob/main/66px_5zu1_230310.jpg?raw=true", "https://github.com/leewanjae/imageAPI_Test/blob/main/New%20Piskel.png?raw=true", "https://github.com/leewanjae/imageAPI_Test/blob/main/monster1.png?raw=true" ] 이렇게 들어가고 있으니.. 이게 말이되나 또한 이미지 순서의 보장도 되지 않는다. 그래서 폴더에 다 집어넣고 그 폴더 URL을 엔드포인트로 해서 이미지를 꺼내서 사용해보겠다. ( 3시간 뒤 ) 근데.. 실패했다. 이거 왜 안되지.....??? GitHubInfo 파일을 만들고 struct랑 enum으로

[GDF 6일차] UIProgressView, Delegate [내부링크]

오늘은~~ 몬스터 피도 만들고, 캐릭터 밑에 공격 버튼을 만들어서 보다 직관적으로 사용자가 사용할 수 있도록 할거다. Hp를 만들려고 서치해본 결과 UIProgressView라는 걸 발견했다. 이걸로 내가 생각한 것들을 만들 수 있을거 같아서 채택해보겠다. 물론 이렇게 사용하라고 만들어 놓은건 아니겠지만... 내가 만들려고하는것에 적합하다면 사용하지 않을 이유가 없다. 일단 도전! 내가 원하는거. 1. 몬스터 피가 100 2. Attack이 들어가면 일정 수치 깎임 3. 몬스터 피가 MaxHp100으로 설정된걸 Attack이 될 때마다 해당 Int를 차감 4. 눈으로 보일 땐 내가 때리면 피가 깎이는 모습 음... Delegate패턴? 이라는게 iOS개발에 상당히 많이 쓰인다고 한다. Delegate 패턴은 delegate를 갖고 있는 객체가 다른 객체에게 자신의 일을 위임하는 형태의 디자인 패턴이다. 상당히 말이 어렵다..... HpBar만드는데 사용하려고 공부해봤는데 굳이? 라는

[GDF 7일차] JoyStick, Event, Navigation, [내부링크]

조이스틱을 만들고 조이스틱과 캐릭터를 연결해서 이동시켜야한다. 오.. 생각보다 참고자료를 금방 찾았다. 역시 구글링이 짱이다. 근데 지난번 이야기했던 delegate패턴이 해당 코드에서 쓰였다. 한번 보자 우선 프로토콜을 설정한다. 이녀석은 어떤 역할을 다른 친구들에게 위임할지 정하는거다. 1. 어디로 움직일지 2. 동작완료 후 추가동작은 어떤것을 할지를 위임한다. protocol JoystickDelegate: AnyObject { func joystickMoved(x: CGFloat, y: CGFloat) func joystickReleased() } 이제 joysticView를 구성해보자 import UIKit class JoystickView: UIView { private let stickView = UIView() private var joystickRadius: CGFloat = 0.0 // 추가: 델리게이트 weak var delegate: JoystickDelegat

[GDF 8일차] JoyStick방향에 따른 이미지, [내부링크]

func joystickMoved(x: CGFloat, y: CGFloat) { // 여기에서 캐릭터를 이동하거나 필요한 작업을 수행합니다. let speed: CGFloat = 5 let dx = speed * x let dy = speed * y // 뷰의 범위를 제한 let newX = front.center.x + dx let newY = front.center.y + dy let maxX = view.bounds.width - front.bounds.width / 2 let maxY = view.bounds.height - front.bounds.height / 2 let minX = front.bounds.width / 2 let minY = front.bounds.height / 2 // 캐릭터 뷰의 새로운 중심 좌표를 설정 front.center = CGPoint(x: min(maxX, max(minX, newX)), y: min(maxY, max(minY, newY)

[GDF 9일차] isUserInteractionEnabled,dismiss [내부링크]

func attckMonsterTapBtn() { let attackTap = UITapGestureRecognizer(target: self, action: #selector(damgeHpTap)) defaultButton.isUserInteractionEnabled = true defaultButton.addGestureRecognizer(attackTap) } isUserInteractionEnabled은 사용자 상호 작용을 허용하거나 비허용하는 데 사용된다. 지금 defaultButton에 몬스터를 공격하는 Event를 추가하는데 isUserInteractionEnabled = true로 변경하니 적용되었다. 그전에는 왜 안됐던거지..? 찾아보니 다수의 상황에서 기본 설정이 true라서 따로 설정 안해도 된다고 하는데 지금 내가 설정하려는 defaultButton은 UIImageView라서 isUserInteractionEnabled를 명시적으로 true로 바꿔야 터치가 먹는

[GDF 10일차] Model [내부링크]

오늘은 이제 Map에서 몬스터가 랜덤 위치에 등장하게 하겠다. func bind() { viewModel.$fieldImage .receive(on: DispatchQueue.main) .sink { [weak self] images in for (index, image) in images.enumerated() { switch index { case 0: self?.mapMonsters.forEach{ $0.image = image} 데이터를 받을 때 mapMonsters 배열에 넣어주고~ func setMonster() { let monsterCount = 5 // 원하는 몬스터 수 for _ in 1...monsterCount { let mapMonster = UIImageView() mapMonster.translatesAutoresizingMaskIntoConstraints = false view.addSubview(mapMonster) let randomTop = CGFl

[GDF 11일차] MVVM 수정.. [내부링크]

지금 내가 MVVM이라고 짠 코드는 뭔가 반쪽짜리 느낌이 있었다.. 왜냐면 Model이랑 VM이 연결이 안된 느낌..? M, VM, V가 하나의 유기체 처럼 연결되는 느낌이 있어야된다고 생각하는데 뭐가 문제지..? 찜찜한 상태였는데 팀원들과 함께 MVVM에 대해서 어떻게 구성해야 할지 꽤나 긴 시간 공부하고 나누었다. 지금 내 코드에서의 문제는 Model을 만들어 놨지만 VM에서 모델을 불러오지 않는다는 점? 나는 VM에서 받은 데이터를 View에서 Model을 불러와 그 안에다가 할당하는 방식으로 사용하고 있었다. 근데 애초에 VM단계에서 Model에 데이터가 할당되게 하고 View에서 그것을 불러오는게 맞다는 것을 알았다. 코드를 수정해보겠다. ---- 코드 전체를 바꾸는게 쉽지 않다... 다음 회차에 이어서..

[GDF 12일차] 나만의 MVVM 정리 + 앱 로직 회의 [내부링크]

코드 리팩토링한다고 꽤나 많은 시간을 사용했다... 추상적으로만 MVVM에 대해서 알고 있었는데 이번에 많은 이해가 됐다. 이틀 간 공부한 MVVM의 흐름도 정리 Model을 짠다. VM에서 Network작업( 서버와 통신 )을 통해 Model의 형식에 데이터를 매핑한다. -이때 @Published를 사용해 Model에 매핑한 데이터의 값이 변화되면 자동으로 감지할 수 있게 한다. @Published var gameModels: [GameModel] = [] -Combine을 통해 서버에서 받은 데이터들의 작업을 처리한다. -내가 봤을 때 VM에 데이터만 잘 넣어주면 어려울게 없다. 3. 이제 View(ViewController)에서 func bind(){} 메소드를 만들고, $기호를 통해 @Published한 모델을 바인딩한다. viewModel.$gameModels.-> 이후 코드 진행. Previous image Next image 지금 백엔드와 직접 연결해 데이터를 받는게 아

[Swift] n번째 원소까지 [내부링크]

n 번째 원소까지 문제 설명 정수 리스트 num_list와 정수 n이 주어질 때, num_list의 첫 번째 원소부터 n 번째 원소까지의 모든 원소를 담은 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 2 ≤ num_list의 길이 ≤ 30 1 ≤ num_list의 원소 ≤ 9 1 ≤ n ≤ num_list의 길이 ___ 입출력 예 num_list n result [2, 1, 6] 1 [2] [5, 2, 1, 7, 5] 3 [5, 2, 1] import Foundation func solution(_ num_list:[Int], _ n:Int) -> [Int] { return Array(num_list[0..<n]) }

[Swift] n개 간격의 원소들 [내부링크]

n개 간격의 원소들 문제 설명 정수 리스트 num_list와 정수 n이 주어질 때, num_list의 첫 번째 원소부터 마지막 원소까지 n개 간격으로 저장되어있는 원소들을 차례로 담은 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 5 ≤ num_list의 길이 ≤ 20 1 ≤ num_list의 원소 ≤ 9 1 ≤ n ≤ 4 입출력 예 num_list n result [4, 2, 6, 1, 7, 6] 2 [4, 6, 7] [4, 2, 6, 1, 7, 6] 4 [4, 7] import Foundation func solution(_ num_list:[Int], _ n:Int) -> [Int] { var result: [Int] = [] for i in stride(from:0, to:num_list.count, by:n){ result.append(num_list[i]) } return result }

MVVM [내부링크]

왜 MVVM이 생겼나? 1. 기존 MVC패턴의 문제 - 애플에서 가이드하던 MVC패턴 - view, view controller 이 둘은 view와 Controller 레이어로 나누어서 설명은 했지만, - 실제로 구현을 할때는 이 둘은 거의 분리되지 않음 - 이러다 보니, View Controller에 많은 로직들이 존재하게 됨 - 프레젠테이션 로직, 비즈니스 로직, 데이터 접근 로직, 등등... - 결국에 Massive ViewController라는 불명예스러운 용어가 따라 붙음 위와 같은 이슈로 발생하는 문제 1. View Controller가 너무 많은 책임을 지고 있음 2. 모델(데이터)를 직접 접근하면서 수정하다보니, 버그에 취약하게 됨 3. 유지보수가 어려움(변경과 수정에 어려움이 많아짐) 기존 문제를 어떻게 해결할까? 1. ViewController를 View 레이어로 생각하자 - View 레이어에서 해야하는 일 - 데이터를 뷰에 표시 - 사용자 인터랙션 받기 2. Vi

MVVM을 넘어서서 [내부링크]

MVVM말고 다른 패턴 1. MVP, VIPER, Ribs, Elm 2. MVVM도 MVVM-Coordinator, MVVM-ViewState 등으로도 나누어서 이야기한다. 그렇지만 1. 디자인 패턴들은 하나의 도구이지 목표가 아니다. 2. 가치 있는 소프트웨어를 일찍 그리고 지속적으로 전달해서 고객을 만족시키는 것 3. 애자일 4대가치 (애자일 소프트웨어 개발 선언문) - 공정과 도구보다 개인과 상호작용 - 포괄적인 문서보다 작동하는 소프트웨어 - 계약 협상보다 고객과의 협력 - 계획을 따르기보다 변화에 대응 문제의 본질 찾기 1. 문제의 본질 - 가치 있는 소프트웨어를 일찍 그리고 지속적으로 전달해서 고객을 만족시키는 것 2. 이를 잘 표현하는게 애자일 개발방법론 3. 그중 로버트 C.마틴(엉글밥)의 저서 "클린 아키텍쳐" 클린 아키텍처란? 1. 레이어를 나누어라 - 엔티티: 비즈니스에 필요한 데이터 모델 - 유즈케이스: 비즈니스 규칙 및 비즈니스 로직을 담당 - 프레젠터 ...

SwiftUI [내부링크]

2019 WWDC에 처음 소개 1. UI작업 시, 새로운 패러다임 - 명령형 -> 선언형 2. 앱 개발이 빨라진다 3. 멀티플랫폼 개발 가능 (tvOS, macOS, watchOS) SwiftUI vs UIKit 1. 듣고 싶은 얘기는 SwiftUI 배우세요, UIKit은 잊어주세요. 2. 그렇지만 현실적인 이유로 UIKit을 배워야한다. - SwiftUI가 UIKit의 모든것을 커버하고 있지 않다. - OS 버전별로 SwiftUI 사용할 수 있는 API가 제한적인 것도 있다. - min SDK가 13이상이어야 함 - 대부분의 회사에서 UIKit 기반의 앱이 있다. - SwiftUI를 통해서 겪는 어려움과 해결책 내용이 적어 공부에 어려움도 있음 3. UIKit부터 배우고 SwiftUI 배우는 것을 추천한다. 4. 그렇지만 결국 애플 제품개발에 있어서, SwiftUI만 사용하는 시대가 올 것 - objective-c -> swift 전환

[SwiftUI] Stack을 이용한 레이아웃 [내부링크]

Stack의 종류 1. HStack : 좌우 2. Vstack : 위아래 3. ZStack : 겹 struct ProfileView: View { var body: some View { Zstack(alignment: .bottom) { Image("ProfilePicture") .resizable() .aspectRatio(contentMode: .fit) HStack { VStack(alignment: .leading) { Text("Rachael Chiseck") .font(.headline) Text("Chief Executive Officer") .font(.subheadline) } Spacer() } .padding() .foregroundColor(.primary) .background(Color.primary .colorInvert() .opacity(0.75)) } } }

SwiftUI Single Source of Truth [내부링크]

이전의 어려움 1. 상태 관리를 위해 중복된 데이터가 여기저기에 있다. 2. 뭐가 진짜인지.. SwiftUI에서는 1. 진짜 상태를 쉽게 관리하게 도와줌 - @State를 이용해서 Single source of truth를 나타낼 수 있음 - @Binding을 통해서 Single source of truth에 접근할 수 있음 2. 상태가 업데이트 되면, 뷰는 자동으로 업데이트 된다 3. SwiftUI 뷰의 상태 정보는 따로 보관하는 장소가 있음 SwiftUI는 단방향 흐름이 중요하다. User -> (User Interaction) ->Action -> (Mutation) -> State -> (updates) -> View -> (Render) -> User 정리 1. SwiftUI에서는 Single source of truth에 의한 상태 관리가 중요 2. SwiftUI에서는 @State를 이용해서 Single source of truth 상태를 나타낼 수 있음 3. @Bindi

UICollectionViewDiffableDataSource [내부링크]

특징 1. iOS 13이상에서 도입 2. UICollectionVIew에 데이터를 제공하고 관리 3. snapshot이라 불리는 객체를 사용해 컬렉션 뷰의 데이터를 업데이트 4. <Item>이 Hashable ... 미완성

CI/CD 개념 이해하기 [내부링크]

CI (Continuous Integration) 1. 개발자가 구현한 코드가 기존과 병합됨 2. 병합된 코드가 올바르게 동작하는지 빌드 & 테스트 3. 빌드 & 테스트 문제가 있다면 수정, 문제가 없다면 배포 진행 CD 1. 지속적 통합을 거친 코드는 신뢰할 수 있기 때문에 배포할 수 있음 2. 지속적 제공(Continuous Delivery)은 CI를 통해서 새로운 소스코드의 빌드와 테스트 병합까지 성공적으로 진행되었다면, 빌드와 테스트를 거쳐 github와 같은 저장소에 업로드하는 것을 의미한다. 3. 지속적 배포(Continuous Deployment)는 이렇게 성공적으로 병합된 내역을 저장소뿐만 아니라 사용자가 사용할 수 있는 배포환경까지 릴리즈하는 것을 의미한다.

Github Action [내부링크]

Github Action 1. CI/CD를 가능하게 해주는 툴 (느린게 단점) 2. Github의 Action 탭에 가면 바로 사용가능 개념 1. Workflow - Github Action 가장 상위 개념 - 자동화 해놓은 작업 과정을 지칭 - yml 파일로 설정 - 하나의 리포에 여러 워크플로우 생성가능 2. Event - workflow를 trigger하는 특정활동이나 규칙 - 특정 브랜치로 push, pr 등 3. Jobs - 독립된 가상머신에서 돌아가는 하나의 처리 단위 - 하나의 워크 플로우는 여러개의 Jobs로 구성됨 - yml 안에 jobs에는 다양한 job이 정의될 수 있음 - 각 job은 run-on을 명시해서 어떤 환경에서 실행되는지 알려주어야함 4. Steps - Job은 여러개의 step으로 실행될 수 있음 - step은 순차적으로 명령어를 수행한다. - run은 스크린트를 실행할 때 쓰임 - uses은 액션을 사용할 때 쓰임 5. Actions - Work

TDD [내부링크]

write a falling test -> Make the test pass -> Refactor -> write a falling test Test Driven Development? 1. Test first 개념에 기반을 둔 개발 방법론 - 짧은 개발 주기 개발 프로세스에 적합 - 사용자 반응에 빠르게 대응 가능 2. 아래의 작업을 반복적으로 함 - write a falling test: 테스트를 작성하고 - Make the test pass: 테스트를 패스시키고 - Refactor: 리팩터링 3. 바꾸어 말하면 - write a falling test: 동작시키고 싶은 것을 작성하고 - Make the test pass: 동작하게 만들고 - Refactor: 더 좋게 만들고 배경: 기존 개발 방법 vs TDD 개발 방법 기존 개발 방법 1. 기획 & 디자인 2. 개발 - 설계 - 기능 개발 (단위가 큼) - 테스트 TDD 개발 방법 1. 기획 & 디자인 2. 개발 - 설계 -

Scrum [내부링크]

애자일 정신 1. 애자일은 프로젝트 관리 및 소프트웨어 개발에 대한 반복적인 접근 방식으로, 팀은 고객에 가치를 더빠르게 덜 복잡한 방법으로 제공할 수 있다. 2. 애자일 팀은 "크게 한 번에" 출시하는데 모든것을 집중하는 대신 더 작은 공략 가능한 단위로 작업을 제공한다. 3. 요구 사항, 계획 및 결과가 지속적으로 평가되므로 팀은 변화에 신속하게 대응할 수 있는 자연스러운 메커니즘을 갖게된다. 스크럼? 1. 애자일 정신을 구현한 한 가지 방법 2. 프로젝트를 애자일하게 운영하게 만드는 방법론 - 스크럼, 칸반, 익스트림 프로그래밍 등 스크럼팀 멤버 구성 1. 적정 인원수는 보통 7명 내외 2. PO (= Project Owner) - 제품의 책임자이며, 백로그를 주로 작성 - 제품에 대한 비즈니스 요구 사항을 정의 할 수 있는 사람 3. 스크럼 마스터 (= Scrum Master) - 스크럼이 잘 진행될 수 있도록 돕는다. - 각 Sprint 별로 처리할 Story Point를

[GDF 1일] SceneDelegate, UITabBarController, NVTitleColor [내부링크]

환경지킴 앱 Green Defense Force [GDF]을 만들기로 했다. 그린 포스 방범대의 캐릭터를 만들어야 하는데.. 인디게임 느낌으로 백수에서 방범대로 점점 진화하는 컨셉의 캐릭터를 만들어봤다. 처음에는 뿅망치와 같은 무기를 들고 점점 멋진 무기로 레벨업 사용자에게 앱 사용의 흥미를 유발하는 요소로 넣을거다. 먼저 StoryBoard기반에서 벗어나 Code기반의 개발을 해보려한다. Main.storyboard를 제거하고 간단한 추가 작업을 통해 코드 기반 개발 환경을 구축했다. SceneDelegate에 가장 처음 앱이 실행되었을 때 실행될 화면을 정해주어야 하는데. import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options conne

[GDF 2일] TabBar Custom, Navigation [내부링크]

1일에 만들었던 TabBar는 흰 배경에선 잘 보이지 않아 TabBar를 보다 잘 보이게 변경하고 싶다. 이미지들의 색을 흰색과 대비되는 검정색이나 친환경적인 느낌을 주는 초록색 계열로 바꾸고 싶다. 아니면.. 탭바에 구역을 눈으로 확인할 수 있도록 색을 주고 흰색으로 할까? 고민이다. tabBar.tintColor = .green (원하는 색) 그냥 단순하게 이렇게 원하는 색으로 변경하면 된다. 고민결과 tabBar.tintColor = .white tabBar.backgroundColor = .black 검은색 배경에 하얀색 틴트컬러를 주었다. 탭바는 이제 마무리 되었고 앱을 사용하다 보면 여러 화면이 쌓이게 되어 개미지옥에 빠지게되는데 사용자로 하여금 자신의 현재 위치를 인식하게 하고 원하는 위치로 손쉽게 돌아갈 수 있도록 네비게이션을 설정하려고 한다. 네비게이션 왼쪽 상단에 뒤로가는 버튼을 나타내는 아이콘과 실제로 뒤로 돌아가는 동작을 부여하고자 한다. 탭바로 구성된 이 화면

[GDF 3일] Util/UIViewCOntroller + Extension , URLSession,Combine, [내부링크]

1일차에 네비게이션 타이틀과 ViewController 설정하는 extension을 만들었는데 어떻게 하면 개발이 추후 진행되었을 때 헷갈리지 않을까? 생각하다 Util폴더에 extension파일을 따로 구성해서 관리하기로 했다. 나는 extension UIViewController하나 였지만 추후 extension한 코드가 많아질 수록 코드를 찾아 다니는게 힘들거 같아서 구조를 바꿔본다. 파일명은 UIViewController + Extension 이전에 코드를 그대로 붙여 넣어준다. import UIKit extension UIViewController { func setNavigationBlackTitleWhiteBg(title: String) { view.backgroundColor = .white navigationItem.title = title navigationItem.largeTitleDisplayMode = .always navigationController?.na

[Swift] 문자 개수 세기 [내부링크]

문자 개수 세기 문제 설명 알파벳 대소문자로만 이루어진 문자열 my_string이 주어질 때, my_string에서 'A'의 개수, my_string에서 'B'의 개수,..., my_string에서 'Z'의 개수, my_string에서 'a'의 개수, my_string에서 'b'의 개수,..., my_string에서 'z'의 개수를 순서대로 담은 길이 52의 정수 배열을 return 하는 solution 함수를 작성해 주세요. 제한사항 1 ≤ my_string의 길이 ≤ 1,000 입출력 예 my_string result "Programmers" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0] import Foundation func solution(_

[Swift] 배열 만들기 1 [내부링크]

배열 만들기 1 문제 설명 정수 n과 k가 주어졌을 때, 1 이상 n이하의 정수 중에서 k의 배수를 오름차순으로 저장한 배열을 return 하는 solution 함수를 완성해 주세요. 제한사항 1 ≤ n ≤ 1,000,000 1 ≤ k ≤ min(1,000, n) 입출력 예 n k result 10 3 [3, 6, 9] 15 5 [5, 10, 15] import Foundation func solution(_ n:Int, _ k:Int) -> [Int] { var result: [Int] = [] for i in 1 ... n { if i >= 1 && i % k == 0 { result.append(i) } } return result.sorted() }

[Swift] 글자 지우기 [내부링크]

글자 지우기 문제 설명 문자열 my_string과 정수 배열 indices가 주어질 때, my_string에서 indices의 원소에 해당하는 인덱스의 글자를 지우고 이어 붙인 문자열을 return 하는 solution 함수를 작성해 주세요. 제한사항 1 ≤ indices의 길이 < my_string의 길이 ≤ 100 my_string은 영소문자로만 이루어져 있습니다 0 ≤ indices의 원소 < my_string의 길이 indices의 원소는 모두 서로 다릅니다. 입출력 예 my_string indices result "apporoograpemmemprs" [1, 16, 6, 15, 0, 10, 11, 3] "programmers" import Foundation func solution(_ my_string:String, _ indices:[Int]) -> String { var str = my_string.map { String($0) } for indice in indice

[Swift] 카운트 다운 [내부링크]

카운트 다운 문제 설명 정수 start_num와 end_num가 주어질 때, start_num에서 end_num까지 1씩 감소하는 수들을 차례로 담은 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 0 ≤ end_num ≤ start_num ≤ 50 입출력 예 start_num end_num result 10 3 [10, 9, 8, 7, 6, 5, 4, 3] import Foundation func solution(_ start:Int, _ end_num:Int) -> [Int] { var result:[Int] = [] for i in end_num ... start { result.append(i) } return result.reversed() }

[Swift] 가까운 1 찾기 [내부링크]

가까운 1 찾기 문제 설명 정수 배열 arr가 주어집니다. 이때 arr의 원소는 1 또는 0입니다. 정수 idx가 주어졌을 때, idx보다 크면서 배열의 값이 1인 가장 작은 인덱스를 찾아서 반환하는 solution 함수를 완성해 주세요. 단, 만약 그러한 인덱스가 없다면 -1을 반환합니다. 제한사항 3 ≤ arr의 길이 ≤ 100'000 arr의 원소는 전부 1 또는 0입니다. 입출력 예 arr idx result [0, 0, 0, 1] 1 3 [1, 0, 0, 1, 0, 0] 4 -1 [1, 1, 1, 1, 0] 3 3 import Foundation func solution(_ arr:[Int], _ idx:Int) -> Int { for (index, value) in arr.enumerated() { if index >= idx && value == 1 { return index } } return -1 }

Combine [내부링크]

왜 Combine이 소개되었는가? 1.기존의 비동기 처리 방식들 - Target / Action - Notification Center - URLSession - KVO - Ad-hoc callbacks 2. 여러 방식들을 조합해서 개발하다보니, 코드가 복잡해짐 3. 통합된 비동기 처리 방식이 필요 4. 일관된 방식으로 비동기 처리 할 수 있는 API를 combine으로 제공 - A unified, declarative API for processing values over time Combine Overview 1. 3가지 주요 컴포넌트 - Publisher : 생산자, 배출자, 크리에이터, 배설자 - Subscriber : 소비자, 구독자, 받는 사람 - Operator : 변경시키는 사람, 마법사, 가공하는 사람 Publisher protocol Publisher { associatedtype Output associatedtype Failure: Error func subsc

ios에서 네트워킹하기 [내부링크]

Concurrency 1. 네트워크 이해하기 전에, concurrency(동시성) 라는것을 알아둘 필요가있다. 2. Concurrency: 여러개의 작업이 동시에 일어나게 보이게 하는것 - 이것은 다른 의미로는 어떤 작업들이 순서에 상관없이 동시에 수행될 수 있음을 이야기한다. Thread 1. 각각의 작업들은 Thread에서 실행된다. - Main-Thread: 화면 표시 및 사용자 인터랙션을 받는 작업 수행 - 데이터를 화면에 보여주기 - 버튼 클릭 이벤트 감지하기 - Background: Main-Thread 외에 작업들 - 네트워크에서 데이터를 다운받을때나 - 디비에서 데이터를 읽어 온다던가 - Custom: 지정된 스레드를 통해서 작업할때 사용 - 카메라를 통해서 들어온 영상데이터 가공 시 - 오디오 데이터 변조 시 Intro 1. HTTP방식으로 네트워크 할 수 있음 2. iOS 네트워크 작업을 도와주는것이 URLSession URLSession 1. URLSession을

[Swift] 리스트 자르기 [내부링크]

리스트 자르기 문제 설명 정수 n과 정수 3개가 담긴 리스트 slicer 그리고 정수 여러 개가 담긴 리스트 num_list가 주어집니다. slicer에 담긴 정수를 차례대로 a, b, c라고 할 때, n에 따라 다음과 같이 num_list를 슬라이싱 하려고 합니다. n = 1 : num_list의 0번 인덱스부터 b번 인덱스까지 n = 2 : num_list의 a번 인덱스부터 마지막 인덱스까지 n = 3 : num_list의 a번 인덱스부터 b번 인덱스까지 n = 4 : num_list의 a번 인덱스부터 b번 인덱스까지 c 간격으로 올바르게 슬라이싱한 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 n 은 1, 2, 3, 4 중 하나입니다. slicer의 길이 = 3 slicer에 담긴 정수를 차례대로 a, b, c라고 할 때 0 ≤ a ≤ b ≤ num_list의 길이 - 1 1 ≤ c ≤ 3 5 ≤ num_list의 길이 ≤ 30 0 ≤ num_list

[Swift] 첫 번째로 나오는 음수 [내부링크]

첫 번째로 나오는 음수 문제 설명 정수 리스트 num_list가 주어질 때, 첫 번째로 나오는 음수의 인덱스를 return하도록 solution 함수를 완성해주세요. 음수가 없다면 -1을 return합니다. 제한사항 5 ≤ num_list의 길이 ≤ 100 -10 ≤ num_list의 원소 ≤ 100 입출력 예 num_list result [12, 4, 15, 46, 38, -2, 15] 5 [13, 22, 53, 24, 15, 6] -1 import Foundation func solution(_ num_list:[Int]) -> Int { for i in 0 ..< num_list.count { if num_list[i] < 0 { return i } } return -1 }

[Swift] 배열만들기 3 [내부링크]

배열 만들기 3 문제 설명 정수 배열 arr와 2개의 구간이 담긴 배열 intervals가 주어집니다. intervals는 항상 [[a1, b1], [a2, b2]]의 꼴로 주어지며 각 구간은 닫힌 구간입니다. 닫힌 구간은 양 끝값과 그 사이의 값을 모두 포함하는 구간을 의미합니다. 이때 배열 arr의 첫 번째 구간에 해당하는 배열과 두 번째 구간에 해당하는 배열을 앞뒤로 붙여 새로운 배열을 만들어 return 하는 solution 함수를 완성해 주세요. 제한사항 1 ≤ arr의 길이 ≤ 100,000 1 ≤ arr의 원소 < 100 1 ≤ a1 ≤ b1 < arr의 길이 1 ≤ a2 ≤ b2 < arr의 길이 입출력 예 arr intervals result [1, 2, 3, 4, 5] [[1, 3], [0, 4]] [2, 3, 4, 1, 2, 3, 4, 5] import Foundation func solution(_ arr:[Int], _ intervals:[[Int]]) ->

[Swift] 2의 영역 [내부링크]

2의 영역 문제 설명 정수 배열 arr가 주어집니다. 배열 안의 2가 모두 포함된 가장 작은 연속된 부분 배열을 return 하는 solution 함수를 완성해 주세요. 단, arr에 2가 없는 경우 [-1]을 return 합니다. 제한사항 1 ≤ arr의 길이 ≤ 100,000 1 ≤ arr의 원소 ≤ 10 입출력 예 arr result [1, 2, 1, 4, 5, 2, 9] [2, 1, 4, 5, 2] [1, 2, 1] [2] [1, 1, 1] [-1] [1, 2, 1, 2, 1, 10, 2, 1] [2, 1, 2, 1, 10, 2] import Foundation func solution(_ arr:[Int]) -> [Int] { var result: [Int] = [] for i in 0 ..< arr.count { if arr[i] == 2 { result.append(i) } } if result.count >= 1 { let startIndex = result[0] le

[Swift] 배열 조각하기 [내부링크]

배열 조각하기 문제 설명 정수 배열 arr와 query가 주어집니다. query를 순회하면서 다음 작업을 반복합니다. 짝수 인덱스에서는 arr에서 query[i]번 인덱스를 제외하고 배열의 query[i]번 인덱스 뒷부분을 잘라서 버립니다. 홀수 인덱스에서는 arr에서 query[i]번 인덱스는 제외하고 배열의 query[i]번 인덱스 앞부분을 잘라서 버립니다. 위 작업을 마친 후 남은 arr의 부분 배열을 return 하는 solution 함수를 완성해 주세요. 제한사항 5 ≤ arr의 길이 ≤ 100,000 0 ≤ arr의 원소 ≤ 100 1 ≤ query의 길이 < min(50, arr의 길이 / 2) query의 각 원소는 0보다 크거나 같고 남아있는 arr의 길이 보다 작습니다. 입출력 예 arr query result [0, 1, 2, 3, 4, 5] [4, 1, 2] [1, 2, 3] import Foundation func solution(_ arr:[Int], _ q

[Swift] n번째 원소부터 [내부링크]

n 번째 원소부터 문제 설명 정수 리스트 num_list와 정수 n이 주어질 때, n 번째 원소부터 마지막 원소까지의 모든 원소를 담은 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 2 ≤ num_list의 길이 ≤ 30 1 ≤ num_list의 원소 ≤ 9 1 ≤ n ≤ num_list의 길이 입출력 예 num_list n result [2, 1, 6] 3 [6] [5, 2, 1, 7, 5] 2 [2, 1, 7, 5] import Foundation func solution(_ num_list:[Int], _ n:Int) -> [Int] { var n = n - 1 return Array(num_list[n...]) }

[Swift] 순서 바꾸기 [내부링크]

순서 바꾸기 문제 설명 정수 리스트 num_list와 정수 n이 주어질 때, num_list를 n 번째 원소 이후의 원소들과 n 번째까지의 원소들로 나눠 n 번째 원소 이후의 원소들을 n 번째까지의 원소들 앞에 붙인 리스트를 return하도록 solution 함수를 완성해주세요. 제한사항 2 ≤ num_list의 길이 ≤ 30 1 ≤ num_list의 원소 ≤ 9 1 ≤ n ≤ num_list의 길이 입출력 예 num_list n result [2, 1, 6] 1 [1, 6, 2] [5, 2, 1, 7, 5] 3 [7, 5, 5, 2, 1] import Foundation func solution(_ num_list:[Int], _ n:Int) -> [Int] { var m = n - 1 var result:[Int] = [] var after = num_list[n...] var before = num_list[...m] result.append(contentsOf: after+b

[Swift] 왼쪽오른쪽 [내부링크]

왼쪽 오른쪽 문제 설명 문자열 리스트 str_list에는 "u", "d", "l", "r" 네 개의 문자열이 여러 개 저장되어 있습니다. str_list에서 "l"과 "r" 중 먼저 나오는 문자열이 "l"이라면 해당 문자열을 기준으로 왼쪽에 있는 문자열들을 순서대로 담은 리스트를, 먼저 나오는 문자열이 "r"이라면 해당 문자열을 기준으로 오른쪽에 있는 문자열들을 순서대로 담은 리스트를 return하도록 solution 함수를 완성해주세요. "l"이나 "r"이 없다면 빈 리스트를 return합니다. 제한사항 1 ≤ str_list의 길이 ≤ 20 str_list는 "u", "d", "l", "r" 네 개의 문자열로 이루어져 있습니다. 입출력 예 str_list result ["u", "u", "l", "r"] ["u", "u"] ["l"] [] import Foundation func solution(_ str_list:[String]) -> [String] { for i in 0..

[Swift] Stack 구현 [내부링크]

struct Stack<T> { // 빈 배열 private var stack: [T] = [] // 요소 추가 mutating func push(_ element: T) { stack.append(element) } // 요소 꺼내기 mutating func pop() -> T? { return stack.popLast() } // 가장 위의 요소 확인 func peek() -> T? { return stack.last } // 스택이 비어있는지 확인 var isEmpty: Bool { return stack.isEmpty } // 스택에 포함된 요소 수 var count: Int { return stack.count } }

[Swift] 버블 정렬, 선택 정렬, 삽입 정렬 [내부링크]

버블 정렬 var arr = [4,2,7,1,9,3] // 버블 정렬 (Bubble Sort) func bubbleSort(_ arr: inout [Int]){ for i in 0..<arr.count { for j in 0..<arr.count - (i + 1) { if(arr[j] > arr[j + 1]) { arr.swapAt(j, j+1) } } } } 선택 정렬 // 선택 정렬 func selectionSort (_ arr: inout[Int]){ for i in 0..<arr.count{ var minIndex = i for j in i+1..<arr.count{ if arr[j] < arr[minIndex]{ minIndex = j } } arr.swapAt(i, minIndex) } } 삽입 정렬 func InsertionSort(_ arr: inout[Int]){ // 가장 첫 번째 원소는 이미 정렬이 되었다고 가정한다. // 따라서 인덱스 1부터 시작 for i i

[Swift] 문자열의 앞의 n글자 [내부링크]

문제 설명 문자열 my_string과 정수 n이 매개변수로 주어질 때, my_string의 앞의 n글자로 이루어진 문자열을 return 하는 solution 함수를 작성해 주세요. 제한사항 my_string은 숫자와 알파벳으로 이루어져 있습니다. 1 ≤ my_string의 길이 ≤ 1,000 1 ≤ n ≤ my_string의 길이 입출력 예 my_string n result "ProgrammerS123" 11 "ProgrammerS" "He110W0r1d" 5 "He110" import Foundation func solution(_ my_string:String, _ n:Int) -> String { var end = my_string.index(my_string.startIndex, offsetBy: n) return String(my_string[..<end]) }

[Swift] 접두사인지 확인하기 [내부링크]

접두사인지 확인하기 문제 설명 어떤 문자열에 대해서 접두사는 특정 인덱스까지의 문자열을 의미합니다. 예를 들어, "banana"의 모든 접두사는 "b", "ba", "ban", "bana", "banan", "banana"입니다. 문자열 my_string과 is_prefix가 주어질 때, is_prefix가 my_string의 접두사라면 1을, 아니면 0을 return 하는 solution 함수를 작성해 주세요. 제한사항 1 ≤ my_string의 길이 ≤ 100 1 ≤ is_prefix의 길이 ≤ 100 my_string과 is_prefix는 영소문자로만 이루어져 있습니다. 입출력 예 my_string is_prefix result "banana" "ban" 1 "banana" "nan" 0 "banana" "abcd" 0 "banana" "bananan" 0 import Foundation func solution(_ my_string:String, _ is_prefix:Stri

[Swift] 문자열 뒤집기 [내부링크]

문자열 뒤집기 문제 설명 문자열 my_string과 정수 s, e가 매개변수로 주어질 때, my_string에서 인덱스 s부터 인덱스 e까지를 뒤집은 문자열을 return 하는 solution 함수를 작성해 주세요. 제한사항 my_string은 숫자와 알파벳으로만 이루어져 있습니다. 1 ≤ my_string의 길이 ≤ 1,000 0 ≤ s ≤ e < my_string의 길이 입출력 예 my_string s e result "Progra21Sremm3" 6 12 "ProgrammerS123" "Stanley1yelnatS" 4 10 "Stanley1yelnatS" import Foundation func solution(_ my_string:String, _ s:Int, _ e:Int) -> String { var myString = my_string.map { String($0) } // ["P", "r", "o", "g", "r", "a", "2", "1", "S", "r", "e

[Swift] 세로 읽기 [내부링크]

세로 읽기 문제 설명 문자열 my_string과 두 정수 m, c가 주어집니다. my_string을 한 줄에 m 글자씩 가로로 적었을 때 왼쪽부터 세로로 c번째 열에 적힌 글자들을 문자열로 return 하는 solution 함수를 작성해 주세요. 제한사항 my_string은 영소문자로 이루어져 있습니다. 1 ≤ m ≤ my_string의 길이 ≤ 1,000 m은 my_string 길이의 약수로만 주어집니다. 1 ≤ c ≤ m 입출력 예 my_string m c result "ihrhbakrfpndopljhygc" 4 2 "happy" "programmers" 1 1 "programmers" import Foundation func solution(_ my_string:String, _ m:Int, _ c:Int) -> String { var arr = my_string.map{String($0)} var result = "" for i in stride(from: c - 1, to:

[Swift] qr code [내부링크]

qr code 문제 설명 두 정수 q, r과 문자열 code가 주어질 때, code의 각 인덱스를 q로 나누었을 때 나머지가 r인 위치의 문자를 앞에서부터 순서대로 이어 붙인 문자열을 return 하는 solution 함수를 작성해 주세요. 제한사항 0 ≤ r < q ≤ 20 r < code의 길이 ≤ 1,000 code는 영소문자로만 이루어져 있습니다. 입출력 예 q r code result 3 1 "qjnwezgrpirldywt" "jerry" 1 0 "programmers" "programmers" import Foundation func solution(_ q:Int, _ r:Int, _ code:String) -> String { var result = "" for (index, element) in code.enumerated() { if index % q == r { result += String(element) } } return result }

최우수상(국무총리상) 수상 [내부링크]

제 11회 범정부 창업경진대회 왕중왕전에서 최우수상(국무총리상)을 수상했다. 5월부터 지금까지 함께해온 팀원에게 너무 고맙고 수고했다는 말을 남기고 싶다. 앞으로 AI와 데이터 처리 부분에 대한 문제를 해결해야 하지만, 지금은 이 즐거움을 만끽하고 싶다. 개발자로써 또 먼 훗날 창업자로써 보다 넓은 시각을 갖게해준 대회였다.

Single Source Of Truth Data, Snapshot, Compositional Layout [내부링크]

Single Source Of Truth Data 1. 기존 구현 방식에서 어떤 데이터(Controller, UI가 각각 데이터를 들고있음)가 참인지 알기 어려웠다. 2. 따라서, 근본적인 문제 해결 방식은 참인 데이터를 한개만 두도록 했다. -> Single Source of Truth 3. 그렇게 제안된 방법이 Diffable Datasource Snapshot 1. 한가지 참인 데이터를 관리하는 객체 2. indexpath를 쓰지않고, 섹션 및 아이템에 대해서 Unique ID를 사용한다. - Unique + Hashable Compositional Layout 1. 기존 UICollectionViewFlowLayout 대부분의 단순 디자인에서는 좋은 역할을 했으나, 2. 점점 복잡한 디자인이 되었을 때, CustomLayout을 그때마다 구현해주어야 했다. 3. 기존 UICollectionView에서 Data, Presentation 구현 방법은 에러가 발생할 수 있음 - U

Navigation, Modality [내부링크]

네비게이션과 모달, 왜 알아야할까? 1. 앱에서 제공해주고 싶은 기능은 많고, 2. 각 기능은 여러 화면을 통해서 기능을 제공해줌 3. 화면 전환간에 사용 context 깨지지 않게 잘 전달하고 싶음 4. 결국, 사용자가 서비스 제공자의 의도를 잘 인지하게 도와주고, 앱 사용성을 쉽게 이해하게 도와주기 위해서 HIG(Human Interface Guideline)에서 크게 두가지 카테고리를 나누어 화면전환을 설명해준다. 1. Modality - 모달은 사용자에게 일시적으로 집중을 요하는 컨텐츠 표시할때 사용 - 따라서, 사용자에게 모달로 띄운 화면이 중요하고, 필요한 경우 액션이 요구 됨을 알려준다. - 화면 나가기 위한 명확한 행동이 요구된다.(닫기 버튼, 화면 스와이프 다운 등) 2. Navigation - 보통 사용자들은 앱의 기능을 탐색할때, 타고 타고 들어가다가 빠져 나올때 당호아하거나 어려움을 겪음 - 이때 네비게이션은 사용자가 당황하지 않게끔, 자연스럽게 지나왔던 곳을