Ver3.5 ๐ Swift ์์กด์ฑ ๊ด๋ฆฌ ์ ๋ต: SPM, CocoaPods, Carthage ํจํค์ง ๋งค๋์ ์ฌ์ธต ๋น๊ต

๐ Swift ์์กด์ฑ ๊ด๋ฆฌ ์ ๋ต: SPM, CocoaPods, Carthage ํจํค์ง ๋งค๋์ ์ฌ์ธต ๋น๊ต
iOS/macOS ๊ฐ๋ฐ์ ํ๋ค ๋ณด๋ฉด ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์์กด์ฑ)๋ฅผ ํ๋ก์ ํธ์ ์ถ๊ฐํด์ผ ํ๋ ์๊ฐ์ด ๋ฐ๋์ ์ด. Alamofire, SnapKit, Kingfisher ๊ฐ์ ์ ๋ช
ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ง์ ์์ค์ฝ๋ ๋ณต๋ถํด์ ์ธ ์๋ ์์ง๋ง... ๊ทธ๊ฑด ์ง์ง ๋
ธ๋ต์ด์์? ๐
๊ทธ๋์ ๋ฑ์ฅํ ๊ฒ ๋ฐ๋ก ํจํค์ง ๋งค๋์ (Package Manager)! ์์กด์ฑ์ ์๋์ผ๋ก ๋ค์ด๋ก๋ํ๊ณ , ๋ฒ์ ์ ๊ด๋ฆฌํ๊ณ , ํ๋ก์ ํธ์ ํตํฉ์์ผ์ฃผ๋ ๋๊ตฌ์ผ.
Swift ์ํ๊ณ์์๋ ํฌ๊ฒ 3๊ฐ์ง ํจํค์ง ๋งค๋์ ๊ฐ ์์ด:
Swift Package Manager
Apple ๊ณต์ ๋๊ตฌ
๊ฐ์ฅ ์ค๋๋ ํจํค์ง ๋งค๋์
Ruby ๊ธฐ๋ฐ
๋ถ์ฐํ ํจํค์ง ๋งค๋์
Go ๊ธฐ๋ฐ
์ด ์ธ ๊ฐ์ง๋ฅผ ์ ๋๋ก ์ดํดํ๋ฉด ํ๋ก์ ํธ ์ํฉ์ ๋ง๋ ์ต์ ์ ์ ํ์ ํ ์ ์์ด. ์ง๊ธ๋ถํฐ ํ๋์ฉ ๋ฏ์ด๋ณด์! ๐ฅ
Swift ์ํ๊ณ์์ ํจํค์ง ๋งค๋์ ๊ฐ 3๊ฐ๋ ๊ณต์กดํ๊ฒ ๋ ๊ฑด ์ฌ์ค ์ญ์ฌ์ ์ธ ์ด์ ๊ฐ ์์ด. ํ์๋ผ์ธ์ผ๋ก ๋ณด๋ฉด ์ดํด๊ฐ ์ฌ์!
Objective-C ์์ ๋ถํฐ ์์. Ruby์ gem ์์คํ ์์ ์๊ฐ๋ฐ์ ๋ง๋ค์ด์ง ์ต์ด์ iOS ํจํค์ง ๋งค๋์ . ๋น์์ ์ง์ง ํ๋ช ์ด์์. ์๋์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ ๋ณต๋ถํ๋ ์๋๋ฅผ ๋๋๊ฑฐ๋ !
Swift๊ฐ ๋ฐํ๋ ํด์ CocoaPods์ ๋จ์ (ํ๋ก์ ํธ ํ์ผ ์์ , ์ค์ ์๋ฒ ์์กด)์ ๋ณด์ํ๊ธฐ ์ํด ๋ฑ์ฅ. "๋น์นจ์ต์ (non-invasive)" ์ฒ ํ์ ๋ด์ธ์. ๊ทผ๋ฐ ๋น๋๊ฐ ๋๋ฆฌ๋ค๋ ๋จ์ ์ด ์์์ ใ ใ
Apple์ด Swift ์คํ์์คํ์ ํจ๊ป ๊ณต์ ํจํค์ง ๋งค๋์ ๋ฅผ ๋ฐํ. ์ฒ์์ iOS ์ง์๋ ์ ๋๊ณ ๊ธฐ๋ฅ์ด ๋ง์ด ๋ถ์กฑํ์. ๊ทผ๋ฐ Xcode 11(2019๋ )๋ถํฐ iOS ์ง์ + Xcode ํตํฉ์ด ๋๋ฉด์ ๊ธ์ฑ์ฅ!
SPM์ Apple์ด ๊ณต์์ผ๋ก ๋ง๋ ํจํค์ง ๋งค๋์ ์ผ. Swift ์ธ์ด ์์ฒด์ ๋ด์ฅ๋์ด ์๊ณ , Xcode์ ์๋ฒฝํ๊ฒ ํตํฉ๋์ด ์์ด์ ๋ณ๋ ์ค์น๊ฐ ํ์ ์์!
SPM์ ๋ชจ๋ ์ค์ ์ Package.swift ํ์ผ ํ๋๋ก ๊ด๋ฆฌ๋ผ. Swift ์ฝ๋๋ก ์์ฑํ๋ ๊ฒ ํน์ง!
// Package.swift ์์
// Swift: Package Description
import PackageDescription
let package = Package(
name: "MyAwesomeApp",
platforms: [
.iOS(.v15),
.macOS(.v12)
],
products: [
.library(
name: "MyAwesomeApp",
targets: ["MyAwesomeApp"]
),
],
dependencies: [
// ์์กด์ฑ ์ถ๊ฐํ๋ ๊ณณ!
.package(
url: "https://github.com/Alamofire/Alamofire.git",
.upToNextMajor(from: "5.8.0")
),
.package(
url: "https://github.com/onevcat/Kingfisher.git",
from: "7.0.0"
),
],
targets: [
.target(
name: "MyAwesomeApp",
dependencies: [
"Alamofire",
"Kingfisher"
]
),
.testTarget(
name: "MyAwesomeAppTests",
dependencies: ["MyAwesomeApp"]
),
]
)
SPM์์ ๋ฒ์ ์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ด ์ฌ๋ฌ ๊ฐ์ง ์๋๋ฐ, ์ด๊ฒ ์ง์ง ์ค์ํด!
| ๋ฐฉ๋ฒ | ์ฝ๋ | ์๋ฏธ |
|---|---|---|
| upToNextMajor | .upToNextMajor(from: "5.0.0") |
5.x.x ๋ฒ์ (6.0.0 ๋ฏธ๋ง) |
| upToNextMinor | .upToNextMinor(from: "5.8.0") |
5.8.x ๋ฒ์ (5.9.0 ๋ฏธ๋ง) |
| exact | .exact("5.8.1") |
์ ํํ 5.8.1๋ง |
| branch | .branch("main") |
ํน์ ๋ธ๋์น ์ต์ ์ปค๋ฐ |
| revision | .revision("abc1234") |
ํน์ ์ปค๋ฐ ํด์ |
https://github.com/Alamofire/Alamofire)SPM์ ์์กด์ฑ์ ์ค์นํ๋ฉด Package.resolved ํ์ผ์ ์๋ ์์ฑํด. ์ด ํ์ผ์ ์ ํํ ๋ฒ์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์์ด์ ํ์๋ค์ด ๋์ผํ ๋ฒ์ ์ ์ฌ์ฉํ๋๋ก ๋ณด์ฅํด์ค.
// Package.resolved ์์ (JSON ํ์)
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a",
"version" : "5.8.1"
}
}
],
"version" : 2
}
Apple ๊ณต์ ์ง์
๋ณ๋ ์ค์น ๋ถํ์
Xcode ์๋ฒฝ ํตํฉ
Swift๋ก ์ค์ ํ์ผ ์์ฑ
๋น ๋ฅธ ๋น๋ ์๋
xcworkspace ๋ถํ์
Linux ์ง์
๋ ๊ฑฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฏธ์ง์
๋ฆฌ์์ค ๋ฒ๋ค ์ฒ๋ฆฌ ๋ณต์ก
Objective-C ํผ์ฉ ์ ์ ํ
๋คํธ์ํฌ ์์กด์ฑ ๋์
Private ํจํค์ง ์ค์ ๋ณต์ก
CocoaPods๋ 2011๋ ๋ถํฐ ์์๋ iOS ์ํ๊ณ์ ํฐ์ค๋๊ฐ์ด์ผ. Ruby๋ก ๋ง๋ค์ด์ก๊ณ , ์ค์ ์ ์ฅ์(CocoaPods Trunk)๋ฅผ ํตํด ํจํค์ง๋ฅผ ๊ด๋ฆฌํด. ํ์ฌ๋ ์๋ง ๊ฐ์ ํ(Pod)์ด ๋ฑ๋ก๋์ด ์์ด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์๋ ๊ฐ์ฅ ๋ง์!
CocoaPods๋ Ruby gem์ผ๋ก ์ค์นํด. macOS์๋ Ruby๊ฐ ๊ธฐ๋ณธ ์ค์น๋์ด ์์ด์ ํฐ๋ฏธ๋์์ ๋ฐ๋ก ์ค์น ๊ฐ๋ฅ!
# CocoaPods ์ค์น
sudo gem install cocoapods
# ๋ฒ์ ํ์ธ
pod --version
# ํ๋ก์ ํธ ์ด๊ธฐํ (Podfile ์์ฑ)
cd /path/to/your/project
pod init
CocoaPods์ ์ค์ ์ Podfile์ ์์ฑํด. Ruby DSL๋ก ์์ฑํ๋ ๊ฒ ํน์ง!
# Podfile ์์
platform :ios, '15.0'
use_frameworks!
# ์ ์ฒด ํ๊ฒ์ ์ ์ฉ
target 'MyAwesomeApp' do
# ๋คํธ์ํน
pod 'Alamofire', '~> 5.8'
# ์ด๋ฏธ์ง ์ฒ๋ฆฌ
pod 'Kingfisher', '~> 7.0'
# UI
pod 'SnapKit', '~> 5.6'
pod 'Then', '~> 3.0'
# ํ
์คํธ ํ๊ฒ
target 'MyAwesomeAppTests' do
inherit! :search_paths
pod 'Quick', '~> 7.0'
pod 'Nimble', '~> 13.0'
end
end
# ๋น๋ ์ค์ ํ์ฒ๋ฆฌ (์ ํ์ฌํญ)
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '5.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
| ์ฐ์ฐ์ | ์์ | ์๋ฏธ |
|---|---|---|
~> |
pod 'Alamofire', '~> 5.8' |
5.8 ์ด์ 6.0 ๋ฏธ๋ง (๋๊ด์ ์ฐ์ฐ์) |
>= |
pod 'Alamofire', '>= 5.0' |
5.0 ์ด์ ๋ชจ๋ ๋ฒ์ |
= |
pod 'Alamofire', '5.8.1' |
์ ํํ 5.8.1๋ง |
:git |
pod 'MyLib', :git => 'https://...' |
Git ์ ์ฅ์ ์ง์ ์ง์ |
์ด๊ฑฐ ํท๊ฐ๋ฆฌ๋ ์ฌ๋ ์ง์ง ๋ง์! ์ฐจ์ด๋ฅผ ๋ช ํํ ์์์ผ ํด ใ ใ
# pod install
# - Podfile.lock์ ๋ช
์๋ ๋ฒ์ ์ผ๋ก ์ค์น
# - ์ฒ์ ์ค์นํ๊ฑฐ๋ ์ ํ ์ถ๊ฐํ ๋ ์ฌ์ฉ
# - ๊ธฐ์กด ํ ๋ฒ์ ์ ๋ณ๊ฒฝํ์ง ์์ (์์ !)
pod install
# pod update
# - Podfile์ ๋ฒ์ ๋ฒ์ ๋ด์์ ์ต์ ๋ฒ์ ์ผ๋ก ์
๋ฐ์ดํธ
# - ํน์ ํ๋ง ์
๋ฐ์ดํธ ๊ฐ๋ฅ
pod update
pod update Alamofire # Alamofire๋ง ์
๋ฐ์ดํธ
# pod outdated
# - ์
๋ฐ์ดํธ ๊ฐ๋ฅํ ํ ๋ชฉ๋ก ํ์ธ
pod outdated
pod update๋ ๋ชจ๋ ํ์ ์ต์ ๋ฒ์ ์ผ๋ก ์ฌ๋ ค๋ฒ๋ ค์ ์์์น ๋ชปํ Breaking Change๊ฐ ์๊ธธ ์ ์์ด. ํน์ ํ๋ง ์
๋ฐ์ดํธํ๊ฑฐ๋, ์ถฉ๋ถํ ํ
์คํธ ํ์ ์ฌ์ฉํ๋ ๊ฒ ์ข์!
๐ Pods/ - ๋ค์ด๋ก๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด ์ ์ฅ๋๋ ํด๋
๐ Podfile.lock - ์ ํํ ๋ฒ์ ์ ๊ธ ํ์ผ (Git์ ์ปค๋ฐ ํ์!)
๐ MyApp.xcworkspace - ์ด์ ์ด๊ฑธ๋ก ํ๋ก์ ํธ ์ด์ด์ผ ํจ!
๐ Pods/Pods.xcodeproj - ํ๋ค์ Xcode ํ๋ก์ ํธ
.xcworkspace ํ์ผ๋ก ํ๋ก์ ํธ๋ฅผ ์ด์ด์ผ ํด. .xcodeproj๋ก ์ด๋ฉด ํ๋ค์ด ์ธ์์ด ์ ๋จ!
๊ฐ์ฅ ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ฑ์ํ ์ํ๊ณ
Podspec์ผ๋ก ์ธ๋ฐํ ์ค์
Private Pod ์ง์
ObjC ์๋ฒฝ ์ง์
Ruby ํ๊ฒฝ ํ์
xcworkspace ๊ฐ์
ํ๋ก์ ํธ ํ์ผ ์์
๋๋ฆฐ pod install
Pods ํด๋ ์ฉ๋ ํผ
Carthage๋ "Simple, decentralized dependency manager for Cocoa"๋ฅผ ํ๋ฐฉํด. CocoaPods์ฒ๋ผ ํ๋ก์ ํธ ํ์ผ์ ๊ฑด๋๋ฆฌ์ง ์๊ณ , ํ๋ ์์ํฌ๋ฅผ ๋น๋ํด์ ์ง์ ๋งํฌํ๋ ๋ฐฉ์์ด์ผ.
# Homebrew๋ก ์ค์น (๊ถ์ฅ)
brew install carthage
# ๋ฒ์ ํ์ธ
carthage version
Carthage๋ Cartfile์ ์์กด์ฑ์ ์ ์ํด. ๋ฌธ๋ฒ์ด ๋งค์ฐ ๊ฐ๋จํจ!
# Cartfile ์์
# GitHub ์ ์ฅ์ (๊ฐ์ฅ ์ผ๋ฐ์ )
github "Alamofire/Alamofire" ~> 5.8
github "onevcat/Kingfisher" ~> 7.0
github "SnapKit/SnapKit" >= 5.6.0
# Git ์ ์ฅ์ ์ง์ ์ง์
git "https://my-private-server.com/MyLib.git" "main"
# ๋ฐ์ด๋๋ฆฌ ํ๋ ์์ํฌ (๋น๋ ์์ด ๋ฐ๋ก ์ฌ์ฉ)
binary "https://my-server.com/MyFramework.json" ~> 2.0
# ์์กด์ฑ ๋น๋ (์ฒ์ ์ค์น ๋๋ Cartfile ๋ณ๊ฒฝ ์)
# iOS์ฉ XCFramework ๋น๋ (Xcode 12+, ๊ถ์ฅ)
carthage bootstrap --use-xcframeworks --platform iOS
# ์
๋ฐ์ดํธ
carthage update --use-xcframeworks --platform iOS
# ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ์
๋ฐ์ดํธ
carthage update Alamofire --use-xcframeworks --platform iOS
# ๋น๋๋ง (๋ค์ด๋ก๋ ์์ด)
carthage build --use-xcframeworks --platform iOS
Carthage๋ ๋น๋ ํ ์๋์ผ๋ก Xcode ํ๋ก์ ํธ์ ํ๋ ์์ํฌ๋ฅผ ์ฐ๊ฒฐํด์ผ ํด. ์ด๊ฒ CocoaPods์ ๊ฐ์ฅ ํฐ ์ฐจ์ด์ !
carthage bootstrap ์คํ ํ Carthage/Build/iOS/ ๋๋ Carthage/Build/XCFrameworks/ ํด๋์ ์์ฑ๋จ
์ฌ๊ธฐ์ .xcframework ํ์ผ์ ๋๋๊ทธ ์ค ๋๋กญ
์ฑ ์คํ ์ด ์ ์ถ ์ ๋ถํ์ํ ์ํคํ ์ฒ ์ ๊ฑฐ๋ฅผ ์ํด ํ์ (XCFramework ์ฌ์ฉ ์ ๋ถํ์ํ ์ ์์)
# Build Phases โ Run Script์ ์ถ๊ฐ (๊ตฌํ ๋ฐฉ์)
/usr/local/bin/carthage copy-frameworks
# Input Files:
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/Kingfisher.framework
MyApp/
โโโ Cartfile โ ์์กด์ฑ ์ ์
โโโ Cartfile.resolved โ ๋ฒ์ ์ ๊ธ (Git ์ปค๋ฐ ํ์!)
โโโ Carthage/
โ โโโ Build/ โ ๋น๋๋ ํ๋ ์์ํฌ (Git ์ปค๋ฐ ์ ํ)
โ โ โโโ iOS/
โ โ โโโ XCFrameworks/
โ โโโ Checkouts/ โ ์์ค์ฝ๋ ์ฒดํฌ์์ (Git ์ปค๋ฐ ๋น๊ถ์ฅ)
โโโ MyApp.xcodeproj โ ์๋ณธ ๊ทธ๋๋ก! (xcworkspace ๋ถํ์)
โโโ Sources/
--use-xcframeworks ์ต์
์ ์ฌ์ฉํ๋ฉด XCFramework ํ์์ผ๋ก ๋น๋๋ผ. XCFramework๋ ์ฌ๋ฌ ํ๋ซํผ(iOS, macOS, Simulator)์ ํ๋์ ํ์ผ๋ก ์ง์ํด์ ํจ์ฌ ํธ๋ฆฌํด!
ํ๋ก์ ํธ ํ์ผ ๋น์นจ์ต
xcworkspace ๋ถํ์
๋ถ์ฐํ (์ค์ ์๋ฒ ์์)
๋น๋ ์บ์ ํ์ฉ ๊ฐ๋ฅ
ํ๋ ์์ํฌ ์ฌ์ฌ์ฉ
์๋ Xcode ์ค์ ํ์
๋น๋ ์๊ฐ ๋งค์ฐ ๋๋ฆผ
Swift ๋ฒ์ ํธํ์ฑ ์ด์
์ ์ ์ค์ด๋๋ ์ง์
์ค์ ๋ณต์ก๋ ๋์
์ ์ด์ ์ธ ๊ฐ์ง๋ฅผ ํ๋์ ๋น๊ตํด๋ณด์! ํ๋ก ์ ๋ฆฌํ๋ฉด ์ดํด๊ฐ ํจ์ฌ ์ฌ์ ใ ใ
| ํญ๋ชฉ | ๐ SPM | ๐ฆ CocoaPods | ๐น Carthage |
|---|---|---|---|
| ์ถ์๋ ๋ | 2015๋ | 2011๋ | 2014๋ |
| ๊ฐ๋ฐ ์ธ์ด | Swift | Ruby | Go |
| ์ค์ ํ์ผ | Package.swift | Podfile | Cartfile |
| ์ ๊ธ ํ์ผ | Package.resolved | Podfile.lock | Cartfile.resolved |
| ๋ณ๋ ์ค์น | โ ๋ถํ์ | โ Ruby gem ์ค์น | โ Homebrew ์ค์น |
| xcworkspace | โ ๋ถํ์ | โ ํ์ | โ ๋ถํ์ |
| ํ๋ก์ ํธ ์์ | ์ต์ | ๋ง์ | ์๋ ์ค์ |
| ๋น๋ ๋ฐฉ์ | ์์ค ๋น๋ | ์์ค ๋น๋ | ํ๋ ์์ํฌ ๋น๋ |
| ์ ์ฅ์ ๋ฐฉ์ | ๋ถ์ฐํ | ์ค์์ง์คํ | ๋ถ์ฐํ |
| Linux ์ง์ | โ | โ | โ |
| Xcode ํตํฉ | โญโญโญโญโญ | โญโญโญ | โญโญ |
| ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ | ์ฆ๊ฐ ์ค | ๊ฐ์ฅ ๋ง์ | ๊ฐ์ ์ค |
์ ํ๋ก์ ํธ ์์ Swift 5.5+ ํ๊ฒฝ Apple ์ํ๊ณ ์ ์ฉ ํ ํ์ ํ๊ฒฝ CI/CD ํ์ดํ๋ผ์ธ
โ 2024๋ ๊ธฐ์ค ์ ํ๋ก์ ํธ๋ผ๋ฉด SPM์ด ๊ฑฐ์ ์ ๋ต์ด์ผ. Apple์ด ๊ณต์ ์ง์ํ๊ณ , Xcode ํตํฉ์ด ์๋ฒฝํ๊ณ , ๋ณ๋ ์ค์น๋ ํ์ ์์ด. ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ SPM์ ์ง์ํ๋์ง๋ง ํ์ธํ๋ฉด ๋จ!
๋ ๊ฑฐ์ ํ๋ก์ ํธ ์ ์ง๋ณด์ SPM ๋ฏธ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ Objective-C ํผ์ฉ ํ๋ก์ ํธ ํ ์ ์ฒด๊ฐ CocoaPods ์ต์
โ ๋ ๊ฑฐ์ ํ๋ก์ ํธ๋ SPM์ ์ง์ํ์ง ์๋ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ผญ ํ์ํ ๋. ๋๋ ํ ์ ์ฒด๊ฐ CocoaPods์ ์ต์ํ๊ณ ๋ง์ด๊ทธ๋ ์ด์ ๋น์ฉ์ด ํด ๋!
๊ธฐ์กด Carthage ํ๋ก์ ํธ ์ ์ง ํ๋ก์ ํธ ํ์ผ ์์ ์ ๋ ๋ถ๊ฐ ๋น๋ ์บ์ ์ต๋ ํ์ฉ ํ์
โ ์์งํ ์ ํ๋ก์ ํธ์์ Carthage๋ฅผ ์ ํํ ์ด์ ๋ ๊ฑฐ์ ์์ด. ๊ธฐ์กด Carthage ํ๋ก์ ํธ๋ฅผ ์ ์ง๋ณด์ํ๋ ์ํฉ์ด ๋๋ถ๋ถ์ผ ๊ฑฐ์ผ.
๋ง์ ํ๋ค์ด CocoaPods์์ SPM์ผ๋ก ์ด์ ํ๊ณ ์์ด. ์ด๋ป๊ฒ ํ๋์ง ์์๋ณด์!
๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ GitHub ์ ์ฅ์์์ Package.swift ํ์ผ์ด ์๋์ง ํ์ธ. ์์ผ๋ฉด SPM ๋ฏธ์ง์!
Xcode 12 ์ด์์ ๊ฐ๋ ฅ ๊ถ์ฅ. SPM์ iOS ์ง์์ด Xcode 11๋ถํฐ ์์๋๊ฑฐ๋ .
๋ง์ด๊ทธ๋ ์ด์ ์ ๋กค๋ฐฑ์ด ํ์ํ ์ ์์ผ๋ ๊ผญ ๋ณ๋ ๋ธ๋์น์์ ์์ ํด!
# 1. CocoaPods ์ ๊ฑฐ
pod deintegrate # Xcode ํ๋ก์ ํธ์์ CocoaPods ์ค์ ์ ๊ฑฐ
pod clean # ์บ์ ์ ๋ฆฌ
# 2. ๊ด๋ จ ํ์ผ ์ญ์
rm Podfile
rm Podfile.lock
rm -rf Pods/
rm MyApp.xcworkspace # xcworkspace ์ญ์ (xcodeproj ๋จ๊ฒจ๋ )
# 3. Xcode์์ SPM ํจํค์ง ์ถ๊ฐ
# File โ Add Package Dependencies...
# ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ GitHub URL ์
๋ ฅ
# 4. ๋น๋ ํ
์คํธ
xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'
CocoaPods๋ ๋ฆฌ์์ค๋ฅผ ์๋์ผ๋ก ๋ฒ๋ค์ ํฌํจ์์ผ์ฃผ์ง๋ง, SPM์ Package.swift์ ๋ช ์์ ์ผ๋ก ๋ฆฌ์์ค๋ฅผ ์ ์ธํด์ผ ํด. ์ด๋ฏธ์ง, ํฐํธ, ์คํ ๋ฆฌ๋ณด๋ ๋ฑ์ ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ฉด ํนํ ์ฃผ์!
CocoaPods๋ ์๋์ผ๋ก ๋ธ๋ฆฌ์ง ํค๋๋ฅผ ๊ด๋ฆฌํด์ฃผ์ง๋ง, SPM์ ์๋ ์ค์ ์ด ํ์ํ ์ ์์ด. ObjC ์ฝ๋๊ฐ ๋ง์ ํ๋ก์ ํธ๋ผ๋ฉด ๋ง์ด๊ทธ๋ ์ด์ ์ด ๋ณต์กํด์ง ์ ์์.
CocoaPods์ post_install ์คํฌ๋ฆฝํธ์์ ํ๋ ๋น๋ ์ค์ ๋ค์ SPM์์๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํด์ผ ํด. ํนํ SWIFT_VERSION์ด๋ IPHONEOS_DEPLOYMENT_TARGET ๊ฐ์ ์ค์ ๋ค.
ํจํค์ง ๋งค๋์ ๋ฅผ ์ ์ฐ๋ ๊ฒ๋ ์ค์ํ์ง๋ง, ์์กด์ฑ ๊ด๋ฆฌ ์์ฒด๋ฅผ ์ ํ๋ ๊ฒ ๋ ์ค์ํด! ์ค๋ฌด์์ ๋ฐ๋ก ์จ๋จน์ ์ ์๋ ํ๋ค์ ๋ชจ์์ ใ ใ
์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ ๋๋ง๋ค ์ ๋ง ํ์ํ๊ฐ?๋ฅผ ๋จผ์ ๋ฌผ์ด๋ด. ๊ฐ๋จํ ๊ธฐ๋ฅ ํ๋๋ฅผ ์ํด ์์ญ MB์ง๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ๊ฑด ์ฑ ํฌ๊ธฐ๋ ํค์ฐ๊ณ , ๋ณด์ ์ทจ์ฝ์ ๋ ธ์ถ ์ํ๋ ๋์ฌ. Swift ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Apple ํ๋ ์์ํฌ๋ก ํด๊ฒฐ ๊ฐ๋ฅํ์ง ๋จผ์ ํ์ธํด๋ด!
Package.resolved, Podfile.lock, Cartfile.resolved ํ์ผ์ ๋ฐ๋์ Git์ ํฌํจ์์ผ์ผ ํด. ์ด ํ์ผ๋ค์ด ์์ผ๋ฉด ํ์๋ง๋ค ๋ค๋ฅธ ๋ฒ์ ์ ์ฐ๊ฒ ๋๊ณ , "๋ด ์ปดํจํฐ์์๋ ๋๋๋ฐ?" ์ํฉ์ด ๋ฐ์ํจ ใ ใ
ํฌํจ ๊ถ์ฅ (์๊ท๋ชจ ํ): ๋คํธ์ํฌ ์์ด๋ ๋น๋ ๊ฐ๋ฅ, CI ์๋ ํฅ์
๋ฏธํฌํจ ๊ถ์ฅ (๋๊ท๋ชจ ํ): ์ ์ฅ์ ํฌ๊ธฐ ์ ์ฝ, ์ถฉ๋ ๊ฐ์
๋๋ถ๋ถ์ ๊ฒฝ์ฐ .gitignore์ Pods/๋ฅผ ์ถ๊ฐํ๊ณ Podfile.lock๋ง ์ปค๋ฐํ๋ ๊ฒ ์ผ๋ฐ์ ์ด์ผ.
# SPM - Package.resolved ํ์ธ ํ ์
๋ฐ์ดํธ
# Xcode โ File โ Packages โ Update to Latest Package Versions
# CocoaPods - ํน์ ํ๋ง ์
๋ฐ์ดํธ
pod update Alamofire # ์ ์ฒด ์
๋ฐ์ดํธ ๋์ ๊ฐ๋ณ ์
๋ฐ์ดํธ
# ์
๋ฐ์ดํธ ํ ๋ฐ๋์ ์ ์ฒด ํ
์คํธ ์คํ!
xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'
ํ์ฌ ๋ด๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํจํค์ง๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ๋ ์์๋๋ฉด ์ข์!
// SPM - Private ํจํค์ง (Package.swift)
.package(
url: "https://github.com/mycompany/private-lib.git",
from: "1.0.0"
)
// โ GitHub/GitLab์์ SSH ํค ๋๋ ํ ํฐ ์ค์ ํ์
// CocoaPods - Private Podspec ์ ์ฅ์
source 'https://github.com/mycompany/private-specs.git'
source 'https://cdn.cocoapods.org/'
pod 'MyPrivateLib', '~> 1.0'
# GitHub Actions์์ SPM ์บ์ ํ์ฉ
- name: Cache SPM packages
uses: actions/cache@v3
with:
path: |
~/Library/Developer/Xcode/DerivedData
.build
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
# CocoaPods ์บ์
- name: Cache CocoaPods
uses: actions/cache@v3
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
ํจํค์ง ๋งค๋์ ์ฐ๋ค ๋ณด๋ฉด ์ง์ง ๋ณ๋ณ ์๋ฌ๊ฐ ๋ค ๋์ ใ ใ ์์ฃผ ๋ง๋๋ ๋ฌธ์ ๋ค ์ ๋ฆฌํด๋ดค์ด!
์์ธ: Package.swift ๋ฌธ๋ฒ ์ค๋ฅ ๋๋ URL์ด ์๋ชป๋จ
ํด๊ฒฐ: Package.swift ๋ฌธ๋ฒ ํ์ธ, URL์ด ์ ํํ GitHub ์ ์ฅ์ URL์ธ์ง ํ์ธ.
swift package describe๋ก ํจํค์ง ์ ํจ์ฑ ๊ฒ์ฌ
์์ธ: ํจํค์ง๊ฐ ํ๊ฒ์ ์ ๋๋ก ์ถ๊ฐ๋์ง ์์
ํด๊ฒฐ: Xcode โ Target โ General โ Frameworks, Libraries, and Embedded Content์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ถ๊ฐ๋์ด ์๋์ง ํ์ธ. ์์ผ๋ฉด + ๋ฒํผ์ผ๋ก ์ถ๊ฐ
ํด๊ฒฐ: Xcode โ File โ Packages โ Reset Package Caches ์คํ. ๊ทธ๋๋ ์ ๋๋ฉด DerivedData ํด๋ ์ญ์ ํ ์ฌ๋น๋
์์ธ: ๋ก์ปฌ CocoaPods ์คํ ์ ์ฅ์๊ฐ ์ค๋๋จ
ํด๊ฒฐ:
pod repo update ์คํ ํ ๋ค์ pod install
์์ธ: ์ฌ๋ฌ ํ ๊ฐ์ ๋ฒ์ ์ถฉ๋
ํด๊ฒฐ:
pod install --verbose๋ก ์์ธ ๋ก๊ทธ ํ์ธ. ์ถฉ๋ํ๋ ํ๋ค์ ๋ฒ์ ๋ฒ์๋ฅผ ์กฐ์ ํ๊ฑฐ๋, pod update๋ก ํด๊ฒฐ ์๋
์์ธ: Podfile.lock๊ณผ ์ค์ ์ค์น๋ ํ์ด ๋ค๋ฆ
ํด๊ฒฐ:
pod install ์ฌ์คํ. ๊ทธ๋๋ ์ ๋๋ฉด Pods ํด๋ ์ญ์ ํ pod install
์์ธ: macOS ๊ธฐ๋ณธ Ruby ๋ฒ์ ์ด ๋๋ฌด ๋ฎ๊ฑฐ๋ ๊ถํ ๋ฌธ์
ํด๊ฒฐ: rbenv๋ rvm์ผ๋ก Ruby ๋ฒ์ ๊ด๋ฆฌ.
rbenv install 3.2.0 && rbenv global 3.2.0
์์ธ: Swift ๋ฒ์ ๋ถ์ผ์น ๋๋ Xcode ๋ฒ์ ๋ฌธ์
ํด๊ฒฐ:
carthage build --verbose๋ก ์์ธ ๋ก๊ทธ ํ์ธ. --use-xcframeworks ์ต์
์ถ๊ฐ ์๋
์์ธ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ฌ Swift ๋ฒ์ ๊ณผ ํธํ๋์ง ์์
ํด๊ฒฐ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ต์ ๋ฒ์ ํ์ธ. ๋๋ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ SPM ๋ฒ์ ์ผ๋ก ๊ต์ฒด ๊ณ ๋ ค
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๋ ๊ฒ๋ ์ค์ํ์ง๋ง, ์ง์ ๋ง๋ค์ด์ ๋ฐฐํฌํ๋ ๊ฒ๋ ์์๋๋ฉด ์ข์! ํนํ ํ ๋ด ๊ณตํต ๋ชจ๋์ ํจํค์ง๋ก ๋ง๋ค๋ฉด ์ฌ์ฌ์ฉ์ฑ์ด ์์ฒญ ์ฌ๋ผ๊ฐ๊ฑฐ๋ ใ ใ
# ์ ํจํค์ง ์์ฑ
mkdir MySwiftPackage
cd MySwiftPackage
swift package init --type library
# ์์ฑ๋๋ ๊ตฌ์กฐ:
# MySwiftPackage/
# โโโ Package.swift
# โโโ README.md
# โโโ Sources/
# โ โโโ MySwiftPackage/
# โ โโโ MySwiftPackage.swift
# โโโ Tests/
# โโโ MySwiftPackageTests/
# โโโ MySwiftPackageTests.swift
# ๋น๋ ํ
์คํธ
swift build
# ํ
์คํธ ์คํ
swift test
// Package.swift - ๋๋ง์ ๋คํธ์ํน ์ ํธ๋ฆฌํฐ ํจํค์ง
import PackageDescription
let package = Package(
name: "NetworkKit",
platforms: [
.iOS(.v15),
.macOS(.v12),
.watchOS(.v8),
.tvOS(.v15)
],
products: [
// ์ธ๋ถ์ ๋
ธ์ถํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
.library(
name: "NetworkKit",
targets: ["NetworkKit"]
),
],
dependencies: [
// ์ด ํจํค์ง๊ฐ ์์กดํ๋ ์ธ๋ถ ํจํค์ง
.package(
url: "https://github.com/Alamofire/Alamofire.git",
.upToNextMajor(from: "5.8.0")
),
],
targets: [
.target(
name: "NetworkKit",
dependencies: ["Alamofire"],
// ๋ฆฌ์์ค ํฌํจ ์
resources: [
.process("Resources")
]
),
.testTarget(
name: "NetworkKitTests",
dependencies: ["NetworkKit"]
),
],
swiftLanguageVersions: [.v5]
)
MAJOR.MINOR.PATCH ํ์์ ๋ฐ๋ผ์ผ ํด. MAJOR๋ Breaking Change, MINOR๋ ํ์ ํธํ ๊ธฐ๋ฅ ์ถ๊ฐ, PATCH๋ ๋ฒ๊ทธ ์์ . SPM์ upToNextMajor๊ฐ ์ด ๊ท์น์ ๊ธฐ๋ฐ์ผ๋ก ๋์ํด!
๋ง์ง๋ง์ผ๋ก ์์ผ๋ก์ ๋ฐฉํฅ์ฑ์ ์ง์ด๋ณด์. ๊ฐ๋ฐ ์ํ๊ณ๋ ๊ณ์ ๋ณํ๋๊น ํธ๋ ๋๋ฅผ ํ์ ํ๋ ๊ฒ ์ค์ํด!
2019๋
Xcode 11์์ iOS ์ง์์ด ์์๋ ์ดํ SPM ์ฑํ๋ฅ ์ด ๊ธ๊ฒฉํ ์ฆ๊ฐํ๊ณ ์์ด. ์ฃผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค(Alamofire, Kingfisher, SnapKit, RxSwift ๋ฑ)์ด ๋ชจ๋ SPM์ ์ง์ํ๊ธฐ ์์ํ๊ณ , Apple๋ ์์ฌ ํ๋ ์์ํฌ๋ค์ SPM์ผ๋ก ๋ฐฐํฌํ๊ธฐ ์์ํ์ด.
2024๋
๊ธฐ์ค ์๋ก์ด iOS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ 90% ์ด์์ด SPM์ ์ง์ํ๊ณ ์์ด!
// Swift 5.9 - ๋งคํฌ๋ก(Macro) ํจํค์ง ์ง์
.target(
name: "MyMacros",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),
// ์กฐ๊ฑด๋ถ ์์กด์ฑ (ํ๋ซํผ๋ณ)
.target(
name: "MyTarget",
dependencies: [
.product(name: "CryptoKit", package: "swift-crypto",
condition: .when(platforms: [.linux]))
]
)
Swift Package Index๋ SPM ํจํค์ง๋ฅผ ๊ฒ์ํ๊ณ ํธํ์ฑ์ ํ์ธํ ์ ์๋ ์ปค๋ฎค๋ํฐ ์ฌ์ดํธ์ผ. CocoaPods์ cocoapods.org์ ๋น์ทํ ์ญํ ์ ํด. Swift ๋ฒ์ ํธํ์ฑ, ํ๋ซํผ ์ง์ ์ฌ๋ถ๋ฅผ ํ๋์ ๋ณผ ์ ์์ด์ ์ง์ง ์ ์ฉํจ!
์ฌ๋ฅ๋ท์์ iOS ๊ฐ๋ฐ ๊ด๋ จ ์ง์์ ๊ณต์ ํ๊ฑฐ๋ ํ๋ฆฌ๋์๋ก ํ๋ํ ๋๋, ์ด๋ฐ ์ต์ ๋๊ตฌ๋ค์ ์ ํ์ฉํ๋ ๊ฒ ๊ฒฝ์๋ ฅ์ด ๋ผ!
CocoaPods๋ ์ฌ์ ํ ์๋ง ๊ฐ์ ํจํค์ง๋ฅผ ๋ณด์ ํ๊ณ ์๊ณ , ๋ ๊ฑฐ์ ํ๋ก์ ํธ์์ ๊ณ์ ์ฌ์ฉ๋ ๊ฑฐ์ผ. ํ์ง๋ง ์ ๊ท ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด CocoaPods ์ง์์ ์ค๋จํ๊ฑฐ๋ SPM๋ง ์ง์ํ๋ ์ถ์ธ์ผ. CocoaPods ํ๋ ์ ์ง๋ณด์ ๋ชจ๋๋ก ์ ํํ ์ํ๋ผ ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ๋ ๊ฑฐ์ ์์ด.
๊ฒฐ๋ก : CocoaPods๋ ์ฃฝ์ง ์์ง๋ง, ์ ํ๋ก์ ํธ์์๋ SPM์ด ์ ๋ต!
Carthage๋ SPM์ ๋ฑ์ฅ์ผ๋ก ์ฌ์ฉ์๊ฐ ๋ง์ด ์ค์์ด. ์ฃผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด Carthage ์ง์์ ์ค๋จํ๋ ๊ฒฝ์ฐ๋ ์๊ธฐ๊ณ ์์. ํ์ง๋ง ์ฌ์ ํ ํน์ํ ์ํฉ(ํ๋ ์์ํฌ ๋น๋ ์บ์ ํ์ฉ, ํน์ ์ํฐํ๋ผ์ด์ฆ ํ๊ฒฝ)์์๋ ์ ์ฉํ๊ฒ ์ฐ์ผ ์ ์์ด.
โข Apple ๊ณต์ ํจํค์ง ๋งค๋์ , Xcode์ ๋ด์ฅ
โข Package.swift๋ก ์ค์ , Package.resolved๋ก ๋ฒ์ ์ ๊ธ
โข ์ ํ๋ก์ ํธ์ ์ฌ์ค์ ํ์ค, 2024๋ ๊ธฐ์ค ๊ฐ์ฅ ๊ถ์ฅ
โข ๋ณ๋ ์ค์น ๋ถํ์, xcworkspace ๋ถํ์
โข 2011๋ ๋ถํฐ ์์๋ ๊ฐ์ฅ ์ค๋๋ ํจํค์ง ๋งค๋์
โข Podfile๋ก ์ค์ , Podfile.lock์ผ๋ก ๋ฒ์ ์ ๊ธ
โข ๊ฐ์ฅ ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ณด์ , ๋ ๊ฑฐ์ ํ๋ก์ ํธ์ ์ ํฉ
โข Ruby ์ค์น ํ์, xcworkspace ํ์ผ ์์ฑ
โข 2014๋ ๋ฑ์ฅ, ๋น์นจ์ต์ ์ฒ ํ์ ํจํค์ง ๋งค๋์
โข Cartfile๋ก ์ค์ , ํ๋ ์์ํฌ ๋น๋ ๋ฐฉ์
โข ํ๋ก์ ํธ ํ์ผ ์์ ์์, ์๋ Xcode ์ค์ ํ์
โข ํ์ฌ ์ฌ์ฉ ๊ฐ์ ์ถ์ธ, ์ ํ๋ก์ ํธ ๋น๊ถ์ฅ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.