Xcode의 Scheme은 iOS, macOS, watchOS 또는 tvOS용 앱을 빌드, 테스트, 프로파일링, 아카이브하는 방법을 정의하는 구성입니다. 각 Scheme에는 고유한 매개변수, 인수, 환경 변수를 가진 일련의 작업(Build, Run, Test, Profile, Analyze, Archive)이 포함됩니다. Apple Developer Documentation, 2025에 따르면 Scheme은 Xcode에서 빌드 구성을 관리하는 주요 도구로, 수동 매개변수 전환을 대체합니다. Xcode는 프로젝트를 처음 열 때 각 타겟에 대한 스킴을 자동으로 생성합니다.
핵심 요점
Xcode의 Scheme은 앱 빌드와 분석을 위한 작업 순서와 그 매개변수를 설명하는 XML 파일(.xcscheme 확장자)입니다. 각 Scheme은 하나 이상의 타겟에 연결되며 각 작업을 어떤 구성(Debug, Release, AdHoc)으로 실행할지 정의합니다. Scheme은 Android의 Build Variant와 동일하지만 더 유연한 구조를 가집니다. 하나의 스킴에 작업마다 다른 타겟을 포함할 수 있습니다.
Xcode는 프로젝트를 처음 열 때 각 타겟에 대한 스킴을 자동으로 생성합니다. 기본 스킴 이름은 타겟 이름과 일치합니다. 프로젝트에 테스트 타겟이 있으면 Xcode는 이를 메인 타겟 스킴의 Test 작업에 자동으로 추가합니다. 여러 타겟(메인 앱 + watchOS + 확장)이 있는 프로젝트의 경우 Xcode는 각각에 대해 별도의 스킴을 생성하지만 모든 타겟을 한 번에 빌드하는 단일 스킴을 만들 수도 있습니다.
스킴은 xcshareddata/xcschemes/ 디렉토리(shared의 경우) 또는 xcuserdata/<user>/xcschemes/(private의 경우)에 저장됩니다. shared 스킴은 Git에 들어가며 전체 팀이 사용합니다. private 스킴은 로컬에 저장되고 동기화되지 않습니다. .xcscheme 파일은 루트 요소 <Scheme>가 있는 XML 형식입니다. 내부에는 각 작업에 대한 블록이 있습니다: BuildAction, TestAction, LaunchAction, ProfileAction, AnalyzeAction, ArchiveAction.
.xcscheme은 수동으로 또는 Xcode를 통해 편집할 수 있는 XML 파일입니다. 주요 요소: <BuildAction>(빌드할 타겟 목록), <TestAction>(테스트 타겟 링크), <LaunchAction>(실행 구성), <ProfileAction>, <AnalyzeAction>, <ArchiveAction>. 각 블록에는 해당 작업에 어떤 구성(Debug/Release)을 사용할지 결정하는 buildConfiguration 속성이 있습니다.
Scheme은 각각 독립적으로 구성할 수 있는 6개의 작업으로 구성됩니다. Build 작업은 어떤 타겟을 어떤 순서로 빌드할지 결정합니다. Run 작업은 어떤 인수, 환경 변수, 어떤 구성으로 앱을 실행할지 결정합니다. Test 작업은 어떤 테스트를 실행하고 어떤 코드 커버리지 옵션을 활성화할지 결정합니다. Profile 작업은 프로파일링을 위해 Instruments 도구로 실행합니다. Analyze 작업은 Clang Static Analyzer로 정적 코드 분석을 수행합니다. Archive 작업은 App Store 게시 또는 AdHoc 배포용 빌드를 생성합니다.
각 작업에 대해 별도의 build configuration을 설정할 수 있습니다. 일반적으로 Run과 Test에는 Debug, Archive에는 Release를 사용합니다. build configuration은 컴파일러 플래그, 최적화, 디버그 정보의 집합을 정의합니다. Xcode는 두 가지 표준 구성을 제공합니다: Debug(최적화 없음, 디버그 심볼 포함)와 Release(최적화 포함, 디버그 정보 없음). 개발자는 project.xcconfig를 통해 사용자 지정 구성을 추가할 수 있습니다.
Archive 작업은 특히 중요합니다. .xcarchive를 생성하고 이를 App Store 또는 AdHoc용 .ipa로 내보냅니다. Archive 작업은 기본적으로 Release 구성을 사용하지만 AdHoc 또는 Distribution으로 전환할 수 있습니다. Archive 작업에는 revealArchiveInOrganizer 플래그도 있습니다. 아카이빙이 완료되면 Xcode는 아카이브로 추가 작업을 위해 Organizer를 엽니다.
<!-- iOS 앱용 .xcscheme 예시 -->
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ABCD1234"
BuildableName = "MyApp.app"
BlueprintName = "MyApp"
ReferencedContainer = "container:MyApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
enableAddressSanitizer = "YES">
</LaunchAction>
</Scheme>
새 스킴 생성은 Xcode 메뉴에서 수행합니다: Product → Scheme → New Scheme 또는 Scheme 패널(Run 버튼 옆)의 "+" 버튼으로. 생성 시 스킴을 만들 타겟을 선택합니다. 기존 스킴을 "duplicate"로 선택하면 Xcode가 해당 설정을 자동으로 복사합니다. 새 스킴은 기본적으로 private으로 저장됩니다. 팀에 공개하려면 Manage Schemes에서 Shared를 활성화해야 합니다.
Edit Scheme 창(Product → Scheme → Edit Scheme)에는 작업 수에 해당하는 6개의 탭이 있습니다. 각 탭에서 build configuration, 실행 인수, 환경 변수, 진단 플래그를 변경할 수 있습니다. Run 탭에는 옵션이 있습니다: executable(실행할 바이너리), wait for executable to be launched(실행된 프로세스 디버깅용), debugger(LLDB 또는 None), launch arguments, environment variables, 확장 옵션(Address Sanitizer, Thread Sanitizer, Main Thread Checker, Memory Management).
진단을 위해 Address Sanitizer(ASan)는 C/C++/ObjC 코드에서 배열 범위를 벗어난 액세스, use-after-free 및 기타 메모리 오류를 감지합니다. Thread Sanitizer(TSan)는 멀티스레드 코드의 데이터 경쟁을 감지합니다. Undefined Behavior Sanitizer(UBSan)는 signed int 오버플로와 같은 정의되지 않은 동작을 감지합니다. 이러한 옵션은 Edit Scheme → Run → Diagnostics에서 사용할 수 있으며 Debug 빌드에서만 작동합니다. 모든 샌티타이저를 활성화하면 시작이 2~3배 느려질 수 있으므로 선택적으로 활성화하는 것이 좋습니다.
일반적인 관행은 각 환경에 대해 별도의 스킴을 만드는 것입니다: Dev, Staging, Production. 각 스킴은 동일한 Build Configuration(Dev의 경우 Debug, Production의 경우 Release)을 사용하지만 실행 인수가 다릅니다: Dev의 경우 -FIRAnalyticsDebugEnabled, -com.apple.CoreData.SQLDebug 1, Production의 경우 인수 없음. 실행 인수는 UserDefaults(ProcessInfo.processInfo.arguments)로 전달되며 앱 시작 시 읽을 수 있습니다. 이를 통해 코드 변경 없이 서버 URL, 로깅 수준, 기능을 전환할 수 있습니다.
shared 스킴은 <project>.xcworkspace/xcshareddata/xcschemes/ 또는 <project>.xcodeproj/xcshareddata/xcschemes/에 저장되며 Git 저장소에 들어갑니다. 팀의 모든 개발자는 Xcode에서 이러한 스킴을 볼 수 있습니다. shared 스킴은 팀 내에서 스킴을 배포하는 유일한 방법입니다. 개발자가 중요한 스킴(예: "Staging Archive")을 만들었지만 Shared로 표시하지 않으면 나머지 팀은 이를 볼 수 없어 혼란이 생깁니다. 각자 자신의 설정으로 자신의 스킴을 만들게 됩니다.
private 스킴은 xcuserdata/<user>/xcschemes/에 저장되며 Git에 들어가지 않습니다. 개인 구성에 유용합니다. 예를 들어 특정 개발자를 위해 모든 샌티타이저가 활성화된 스킴 등입니다. private 스킴에는 프로젝트 빌드가 의존하는 중요한 설정이 포함되어서는 안 됩니다. 개발자가 프로젝트를 떠나면 해당 private 스킴은 사라집니다. 권장사항: CI/CD에서 사용되고 최소 두 명의 개발자가 사용하는 모든 스킴은 Shared로 만드세요.
스킴 관리는 Manage Schemes(Product → Scheme → Manage Schemes)를 통해 수행합니다. 창에는 프로젝트의 모든 스킴, 상태(Shared/Private), 추가/제거용 +/− 버튼이 표시됩니다. Shared 체크박스는 팀에 대한 스킴 표시 여부를 전환합니다. Git 충돌(두 개발자의 .xcscheme 변경)의 경우 병합을 신중하게 해결해야 합니다. XML 파일에 다른 타겟 식별자가 포함될 수 있기 때문입니다. 병합 중 잠긴 파일(git lfs 또는 .gitattributes)에 .xcscheme을 추가하는 것이 좋습니다.
Arguments(인수)는 Scheme에서 실행 시 앱에 전달되는 문자열(ProcessInfo.processInfo.arguments)과 환경 변수(ProcessInfo.processInfo.environment)입니다. 인수는 플래그에 사용됩니다: -AppleLanguages (ru), -AppleLocale ru_RU로 러시아어 로케일을 시뮬레이션하거나 -FIRDebugEnabled로 Firebase 디버깅을 활성화합니다. 환경 변수는 구성에 사용됩니다: API_BASE_URL=http://localhost:3000, LOG_LEVEL=debug.
다른 환경에서 기능(피처 플래그)을 관리하려면 Arguments + Build Configuration의 조합을 사용합니다. Dev 스킴에서는 인수 -FeatureFlagNewOnboarding YES를 설정하고 Production에서는 -FeatureFlagNewOnboarding NO를 설정합니다(또는 인수 없음). 코드에서 확인: UserDefaults.standard.bool(forKey: "FeatureFlagNewOnboarding"). 이 접근 방식은 코드를 변경하지 않고 프로덕션 값을 커밋하지 않고 staging에서 기능을 점진적으로 활성화할 수 있게 합니다.
중요: Scheme의 인수와 환경 변수는 Info.plist의 값을 재정의합니다. Info.plist에 API_URL이 지정되고 Scheme에 Run 작업용 API_URL=http://localhost가 있으면 Xcode에서 실행할 때 Scheme의 값이 사용됩니다. 기기에서 실행할 때(Xcode가 아닌 경우)는 Info.plist의 값이 사용됩니다. 이는 로컬 개발에 편리하지만 Scheme 변수는 빌드에 들어가지 않는다는 점을 기억해야 합니다. Xcode를 통해서만 실행할 때 작동합니다.
import Foundation
struct AppEnvironment {
var apiBaseURL: String {
ProcessInfo.processInfo.environment["API_BASE_URL"]
?? Bundle.main.object(forInfoDictionaryKey: "API_BASE_URL") as? String
?? "https://api.production.com"
}
var isDebugMode: Bool {
ProcessInfo.processInfo.arguments.contains("-DebugModeEnabled")
}
var isNewOnboardingEnabled: Bool {
UserDefaults.standard.bool(forKey: "FeatureFlagNewOnboarding")
}
}
// 시작 시 사용
let env = AppEnvironment()
NetworkConfig.shared.configure(baseURL: env.apiBaseURL)
CI/CD(GitHub Actions, Jenkins, GitLab CI)에서 Scheme은 xcodebuild 명령의 주요 인수로 사용됩니다. 예: xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release -sdk iphoneos archive. -scheme 플래그는 사용할 스킴을 지정합니다. xcodebuild는 .xcscheme 파일에서 build configuration, 타겟, 빌드 순서를 포함한 모든 설정을 읽습니다. 이를 통해 CI/CD가 로컬 IDE와 동일한 매개변수로 앱을 빌드함을 보장합니다.
CI/CD에는 shared 스킴이 중요합니다. 스킴이 Shared가 아니면 xcodebuild가 저장소에서 찾지 못하고 "Scheme not found" 오류로 빌드가 실패합니다. 규칙: CI/CD를 설정하기 전에 사용되는 모든 스킴이 Shared로 표시되었는지 확인하세요. 두 번째 규칙: CI/CD에서 기본 스킴을 사용하지 마세요(Xcode는 첫 번째 스킴을 자동으로 선택합니다). 항상 -scheme 플래그로 스킴 이름을 명시적으로 전달하세요.
여러 스킴을 병렬로 빌드하려면(예: 앱과 watchOS 확장) xcodebuild를 순차 또는 병렬로 실행할 수 있습니다. 최신 CI 시스템은 매트릭스를 통해 서로 다른 스킴의 빌드를 병렬화할 수 있습니다. 하나의 작업이 iOS 앱을 빌드하고 다른 작업이 watchOS 확장을 빌드합니다. 이렇게 하면 두 개의 병렬 에이전트에서 총 빌드 시간이 15분에서 8분으로 줄어듭니다. 마지막에 아티팩트는 xcodebuild -exportArchive로 단일 .xcarchive로 결합됩니다.
#!/bin/bash — xcodebuild로 CI/CD 빌드
# 1. 정리 및 빌드
xcodebuild clean archive \
-workspace "MyApp.xcworkspace" \
-scheme "MyApp Production" \
-configuration Release \
-sdk iphoneos \
-archivePath "build/MyApp.xcarchive" \
CODE_SIGN_STYLE="Manual" \
PROVISIONING_PROFILE_SPECIFIER="match AppStore"
# 2. IPA로 내보내기
xcodebuild -exportArchive \
-archivePath "build/MyApp.xcarchive" \
-exportPath "build/ipa" \
-exportOptionsPlist "ExportOptions.plist"
자주 묻는 질문
보통 2-3개의 스킴이면 충분합니다: Development(Debug), Staging(테스트 서버용 인수 포함), Production(Release). 모듈형 라이브러리의 경우 테스트 설정이 있는 스킴 하나. 스킴을 너무 많이 만들지 마세요. 새 스킴마다 유지 관리가 필요합니다.
Build Configuration(Debug/Release)은 .xcconfig에 정의된 컴파일러 플래그 집합입니다. Scheme은 각각 Build Configuration을 참조하는 작업 집합입니다. 스킴은 "실행 시 Debug 사용"이라고 말하고 구성은 "Debug는 최적화 없음, 심볼 포함"을 정의합니다.
인수는 ProcessInfo.processInfo.arguments와 UserDefaults로 들어갑니다(인수가 하이픈으로 시작하는 경우). 환경 변수는 ProcessInfo.processInfo.environment로 들어갑니다. 코드에서: -FeatureFlag YES 형식의 인수의 경우 UserDefaults.standard.bool(forKey: "FeatureFlag").
네, Build Action에 여러 타겟을 추가할 수 있습니다. 예를 들어 "App + Watch + Widget" 스킴은 세 타겟을 모두 순차적으로(parallelizeBuildables=NO인 경우) 또는 병렬로(YES) 빌드합니다. 앱 아카이브에는 메인 타겟이면 충분합니다. 나머지는 종속성으로 빌드됩니다.
Swift Package Manager는 스킴을 대체하지 않습니다. 스킴은 여전히 SPM 종속성을 어떤 구성으로 빌드할지, 어떤 테스트를 실행할지, 어떻게 아카이브할지 정의합니다. SPM 패키지는 자체 스킴을 가질 수 있으며 패키지를 추가하면 프로젝트에 자동으로 가져옵니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.