숫자야구를 만들면서 조건에 맞는 답 리스트를 csv로 제공하면 1. 관리도 쉽고, 2. 랜덤한 정답을 뽑기도 쉽고, 3. 정답을 손쉽게 여러개 뽑을 수도 있다는 생각에, Resources
폴더 안에 csv
파일을 읽을 수 있는 기능을 넣으려고 했다. 디렉토리와 코드는 이렇게 구성했다.
main.swift
NumberBaseball/
├── Sources/
│ ├── main.swift
│ ├── AnswersList.swift
│ └── AnswerGenerator.swift
└── Resources/
└── answersList.csv
import Foundation
class AnswersList {
func read() -> [String] {
let resourcePath = "../Resources/answersList.csv"
do {
// 파일 내용을 문자열로 읽기
let fileContents = try String(contentsOfFile: resourcePath, encoding: .utf8)
return fileContents.components(separatedBy: "\n").filter { !$0.isEmpty }
} catch {
print("Error occured while reading the file: \(error)")
return []
}
}
}
there is no such file - 파일이 없다고 한다 |
---|
대충 오류를 검색해보니, 프로젝트의 빌드 설정에서 Copy Bundle Resources
에 포함되어있는지 확인하라고 한다.
[확인 방법] 해당 파일의 File Inspector
에 가서 Target Membership
에서 타겟이 체크가 되어있는지 확인
File Inspector | Target Membership에 Target 추가 시도 (실패: 체크박스가 비활성화되어있음) ❌ |
---|---|
파일을 추가한 방식이 잘못된 건 아닐까? 나는 파인더에서 폴더를 직접 찾아 csv
파일을 넣었다.
이 파일을 삭제하고 Xcode의 상단 메뉴 File > Add Files to "NumberBaseball"...
로 파일을 넣어봤다. -> ❌
빌드 설정에서 직접 Copy Bundle Resources
를 찾기로 했다.
Build Phases에 Copy bundle Resources는 없고 Copy Files만 있다. | 일단 파일 추가는 가능했다. | Target Membership ✅ |
---|---|---|
"번들(Bundle)에 넣은 파일은 이렇게 경로를 설정해주면 상대경로를 입력해주지 않아도 찾아준다"
func load() -> String? { if let filePath = Bundle.main.path(forResource: "answersList", ofType: "csv") { do { // 파일 내용을 문자열로 읽기 let fileContents = try String(contentsOfFile: filePath, encoding: .utf8) return fileContents } catch { print("Error occurred while reading the file: \(error)") } } else { print("File not found in the bundle.") } return nil }
하지만 이 방법도 if let
의 else
문으로 넣어둔 "File not found in the bundle." 메시지가 뜨면서 파일 인식에 실패했다. -> ❌
Copy Bundle Resources
가 아니었던 게 문제였나보다. 검색해보니, 내 NumberBaseball의 template인 Command Line Tool 프로젝트는 번들 구조가 아닌 단일 실행 파일로 컴파일되기 때문에, 리소스 파일을 번들에 포함하는 방식이 다르다고 한다. 그래서 파일을 상대 경로나 절대 경로로 읽을 수 밖에 없다.
Command Line Tool 프로젝트는 번들 구조를 사용할 수 없다 |
---|
Command Line Tool 프로젝트라도 같은 디렉토리에 main.swift와 answersList.csv 파일이 같이 있으면 인식할 수 있을 것이라 생각했다. 하지만 해당 위치에 파일을 추가하고 경로도 수정했지만 똑같이 파일을 인식하지 못했다. -> ❌
일단 해당 파일을 Copy Files
에는 포함시킨 상태로 기존의 상대 경로를 이용하는 코드에 아래 코드를 넣어서,
명령어가 실행되는 실제 폴더 위치를 확인해보기로 했다.
print("Current Directory: \(FileManager.default.currentDirectoryPath)")
Current Directory로 나온 경로가 실제 파일이 실행되고 있는 경로 |
---|
해당 경로 | 해당 경로/NumberBaseball.swiftmodule |
---|---|
폴더를 아무리 뒤져봐도 csv 파일을 찾을 수 없다. -> ❌
여기까지 삽질했으면 충분하다고 느꼈다. 그냥 별도의 swift
파일로 넣기로 했다. (하하하..) -> ✅
csv
파일을 코드로 변환하는 것은 ChatGPT를 이용했다. (사실 csv
파일 생성도 ChatGPT를 이용했다)
기존에 쓴 파일 읽기 코드가 아깝긴 했지만, 공들여 쌓은 코드보다 제대로 작동하는 코드가 더 중요하다.
다음에 Command Line Tool
에서 파일 읽기를 시도하려면, 오늘 한 삽질은 건너뛰고 컴파일된 프로젝트에 별도의 Resources나 Data 등의 폴더를 함께 둬서 읽게 하도록 시도해봐야겠다 (컴파일한 후 시도해야된다는 점이 무척 마음에 안들긴 한다).
다음에 검색할 땐 꼭 여러 맥락을 파악한 후 해야겠다. 프로젝트의 template이 다르다던가, Xcode의 버전이 다르다던가, 특정 라이브러리를 사용한다던가.. 등 정말 많은 맥락에 따라 검색 범위가 달라진다. 그렇기에 문제를 접근할 때는 몇 발짝 벗어나 넓은 시야를 가지는 습관을 들여야겠다. 어쩌면 효율적인 검색을 위해 체크리스트를 만들어 두는 게 좋을 것이다. 하지만 그것도 꽤 데이터가 쌓여야 만들 수 있는 리스트일테니, 쉽사리 만들거나 알고리즘으로 구성할 생각도 못하겠다. 누군가가 만들어놨을지도?
문득, 맥락을 이해한다는 것은 무척 인간적인 행위라는 생각이 든다. "Make sure we're on the same page"
- 누군가와 대화할 때 항상 중요하게 생각하는 말이다. '서로 다른 자료를 보고 있진 않은가?', '문제 이해에 관해 전제가 서로 다르진 않은가?', '한 쪽은 문제 해결, 한 쪽은 감정 해소에 초점을 맞추고 있진 않은가?', '두 사람의 가치관이 전혀 다르고, 그것을 서로 인식하지 못하고 있는가?' 등등... 우리 인간은 수많은 맥락을 당연하게 여기고 대화를 한다. 이러한 맥락들을 사전에 체크하고 대화에 돌입하는 스킬은, 경험을 요구하기에 어려우면서도 그 효율성에 있어 아주 중요한 스킬이라고 생각한다. 무언가를 검색하거나 코드를 짤 때도 마찬가지이다. '컴퓨터는 내 머릿속 맥락을 이해하지 못한다.'라는 배경을 파악하고 있을 때, 검색어와 코드는 더 구체적이고 정교해진다. "컴퓨터는 바보다"라고 장난스럽게 생각해도 좋을 수준이다 >:D ('맥락을 이해하지 못한다'는 맥락이라니, 이런 말장난이 나는 너무 좋다)
제가 cgv는 아는데요 csv는 어 음