알고리즘 풀 때 Xcode 셋팅방법

소혜 (Sohye)
xohxe (김소혜)· October 10, 2023
초심자를 위한 Xcode swift 문제해결방법들
  • Xcode 초기 셋팅
  • 알고리즘 풀 때 Xcode 셋팅방법
  • Xcode 에서 알고리즘 풀기

    readLine 함수를 사용해야하는 경우(입력값을 받아야하는 경우)에는 플레이그라운드 대신, Xcode의 Command Line Tool을 사용해야한다.

    그런데 main.swift이외의 다른 파일에서 실행하면, 해당 메시지가 뜬다.

    Error!

    swift expressions are not allowed at the top level

    Xcode Command Line Tool 에서 Swift 알고리즘 공부를 하는데 파일을 분리하고, main.swift 이외의 파일에서 실행하니 빌드되지않았다. VS code에서는 여러 개 파일을 만들어 터미널로 실행해도 문제가 없었던 것 같은데, 정말 이것때문에 몇일은 삽질했다.

    결론부터 말하자면
    Xcode에서는 main.swift가 엔트리 포인트 이기에

    1. main.swift를 제거하거나,
    2. main.swiftTarget Membership은 해제하고
      다른 파일에서만 Target Membership을 설정한채 빌드하면,

    오류가 발생했던 것이다.

    C언어에 뿌리를 둔 모든 애플리케이션은 main()함수를 통해 시작되는데, 이를 entry point(엔트리 포인트, 시작 진입점)이라고 한다. main.swift 파일도 엔트리포인트로 정해져있기에, Build Failed가 계속 발생하는 것이다.

    “main.swift” file can contain top-level code, and the order-dependent rules apply as well. In effect, the first line of code to run in “main.swift” is implicitly defined as the main entrypoint for the program.

    공식 문서에서 main.swift를 재정의할 수 없다는 것을 확인하고 함수를 실행시키려면 main.swift을 통해야할 수 밖에 없다는 걸 알게되었고, 그렇다면 swift파일을 한 프로젝트 안에서 깔끔하게 정리하려면 어떻게 해야할까 찾아봤는데 고민하게되었다.

    1. 실행시킬 문제만 main.swift에 두기

    실행시킬 문제만 main.swift에 두고 실행시키고, 푼 문제는 다른 파일로 옮겨서 분리 해주는 방법으로 개인적으로 생각하기에 제일 간단한 방법이다.

    main.swift
    COPY
    import Foundation
        func randomInt() -> Int{
            return Int.random(in: 1...100)
        }
      // 함수 예제 07
        func getDivisor(_ number: Int) -> [Int] {
            var divisors : [Int] = []
            for k in 1...number{
                if number % k == 0{
                    divisors.append(k)
                }
            }
            return divisors
        }
    
        print("\(randomValue)의 약수들 \(getDivisor(randomValue))")
    

    여기서 주의할 점은 **이미 푼 다른 파일에서는 Target Membership을 꼭 해제시켜주고**,
    실행시킬 문제 코드만 main.swift로 옮겨서 실행시켜야한다.

    2. 딕셔너리로 만들어 함수 호출하기

    이 방법을 딕셔너리를 이해해야 구현가능한 방법일테지만 제일 깔끔한 방법이라 생각한다.
    실제로 내가 공부하고 있는 내용을 GitHub에 올려두었으며, 참고하시면 이해하는데 도움이 될 것 같다!

    2-1. 디렉토리 파일 분리

    먼저 폴더는 주제별로, 문제마다 번호를 매겨 분리해준다. 나는 아래처럼 구분해보았다.

    디렉토리 예시

    2-2. 문제별 함수 생성

    매일 풀어본 문제들을 한 파일에 저장하기에는 가독성이 안좋아서 파일을 분리했다.

    question/array01.swift
    COPY
    import Foundation
    
    func for_07(){
        // 함수 예제 07
        func getDivisor(_ number: Int) -> [Int] {
            var divisors : [Int] = []
            for k in 1...number{
                if number % k == 0{
                    divisors.append(k)
                }
            }
            return divisors
        }
    
        print("\(randomValue)의 약수들 \(getDivisor(randomValue))")
    }

    2-3. Main.swift 에서 딕셔너리

    딕셔너리를 이용해서 문제들을 저장시켜준다.

    여기서 유의할 점은 함수의 형식에 따라 Type이 달라지므로, 나는 폴더마다 타입을 다르게 설정했다.

    main.swift
    COPY
    import Foundation
    
    var inputA = inputLine("1번째 수:")
    var inputB = inputLine("2번째 수:")
    
    let questionDict: [String : () -> Void] = [
        ...
        "함수 예제 06" : func_06,
        "함수 예제 07" : func_07,
    ]
    
    
    func question(_ question: String) {
        print("======== Q \(question) 정답 ========")
        if let closure = questionDict[question] {
            closure()
        }else{
            print("Question이 없어요.")
        }
    }
    
    // 실행시킬 문제번호 입력
    let printQuestion = "함수 예제 01"
    question(printQuestion)

    그렇다면 결과값은 다음과 값이 출력된다.

    ======== Q 함수 예제04 정답 ========
    a : 1
    b : 2
    a의 b제곱은 1
    

    아 그리고 이 방법을 사용할 때는 꼭 Target mebership에 체크해줘야한다!!!!

    2-4. 자주쓰는 Readline함수 정리

    자주쓰는 함수는 readline도 함께 분리해두면 유용하게 사용할 수 있다.
    나는 Func 폴더를 별도로 만들어 추가해두었다.

    COPY
    // 입력값을 받을 Readline 함수 모음
    func inputLine(_ message: String) -> () -> Int {
        return{
            print(message , terminator: " ")
            return Int(readLine()!)!
        }
    }
    
    func inputString(_ message: String) -> () -> String {
        return{
            print(message, terminator: " ")
            return String(readLine()!)
        }
    }
    
    func inputInt(_ num1:Int, _ num2:Int) -> () -> Int {
        return{
            print("\(num1)+\(num2)=", terminator: " ")
            return Int(readLine()!)!
        }
    }
    
    

    참고글

    1. Xcode를 이용해 백준문제 풀기
    다음 게시물
    document is not defined

    © 2023 - 2024 xohxe. All Rights Reserved.