Ver3.5 ๐ Apple ์ํ๊ณ์ Swift ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ฐ์ ๋ฐฉํฅ

๐ Apple ์ํ๊ณ์ Swift ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ฐ์ ๋ฐฉํฅ
iOS ยท macOS ยท watchOS ยท visionOS๋ฅผ ์์ฐ๋ฅด๋ Swift์ ์งํ ์ฌ์ ๐
์ผ ์์งํ ๋งํด์... Apple ์ํ๊ณ ๊ฐ๋ฐ ๊ณต๋ถํ๋ค ๋ณด๋ฉด ์ง์ง "์ด๊ฒ ๋ค ์ฐ๊ฒฐ์ด ๋๋ค?!" ํ๋ ์๊ฐ์ด ์ค๊ฑฐ๋ ใ
ใ
ใ
๐คฏ
iPhone ์ฑ ๋ง๋ค๋ค๊ฐ Mac ์ฑ๋ ๋๊ณ , Apple Watch๋ ๋๊ณ , ์ฌ์ง์ด Vision Pro๊น์ง?!
์ค๋์ Swift ์ธ์ด์ Apple ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ(IDE)์ด ์ด๋ป๊ฒ ๋ฐ์ ํด์๊ณ , ์์ผ๋ก ์ด๋๋ก ๊ฐ๋์ง๋ฅผ ์ง์ง ํฉํธ ๊ธฐ๋ฐ์ผ๋ก ๋ฑ๋ฑ์ด ํํค์ณ๋ณผ๊ฒ ๐
Swift ์ ๋ฌธํ๋๋ฐ ์ ์ฒด ๊ทธ๋ฆผ์ด ์ ๊ทธ๋ ค์ง๋ ๋ถ / Xcode ์ฐ๋๋ฐ ๊ธฐ๋ฅ์ ๋ฐ๋ ๋ชจ๋ฅด๋ ๋ถ / Apple ์ํ๊ณ ๊ฐ๋ฐ์ ๋ฏธ๋๊ฐ ๊ถ๊ธํ ๋ถ / ๊ทธ๋ฅ ๊ฐ๋ฐ ํธ๋ ๋ ํ์ ํ๊ณ ์ถ์ ๋ถ ๋ชจ๋ ํ์ ๐
๐ฑ Swift ํ์ ๋ฐฐ๊ฒฝ โ "Objective-C์ผ, ์ด์ ์ข ์ฌ์ด"
2014๋
WWDC(Apple ์ธ๊ณ ๊ฐ๋ฐ์ ์ปจํผ๋ฐ์ค)์์ ํฌ๋ฆฌ์ค ๋ํธ๋(Chris Lattner)๊ฐ Swift๋ฅผ ๋ฐํํ์ ๋, ๊ฐ๋ฐ์๋ค ๋ฐ์์ด ์ง์ง ใ
ใ
ใ
"์ด๊ฒ ๋ญ์ผ?" ์์ "์ค ์ด๊ฑฐ ์ธ ๋งํ๋ฐ?" ๋ก ๋ฐ๋๋ ๋ฐ ๋ฑ 5๋ถ ๊ฑธ๋ ธ๋ค๊ณ ํจ ๐
๊ทธ ์ ๊น์ง Apple ํ๋ซํผ ๊ฐ๋ฐ์ Objective-C๊ฐ ์ง๋ฐฐํ๊ณ ์์์ด. 1980๋
๋์ ๋ง๋ค์ด์ง ์ธ์ด์ธ๋ฐ, ์์งํ ๋ฌธ๋ฒ์ด ์ข... ๋
ํนํ๊ฑฐ๋ .
// Objective-C ์คํ์ผ (์๋ ๋ฐฉ์)
NSString *greeting = @"Hello, World!";
NSLog(@"%@", greeting);
// Swift ์คํ์ผ (ํ๋์ )
let greeting = "Hello, World!"
print(greeting)
๋ด๋ด, ์ฐจ์ด๊ฐ ๋๊ปด์ง์ง? ใ
ใ
Swift๋ ์ฒ์๋ถํฐ ์์ ์ฑ(Safety), ์๋(Speed), ํํ๋ ฅ(Expressiveness) ์ธ ๊ฐ์ง๋ฅผ ํต์ฌ ์ฒ ํ์ผ๋ก ์ค๊ณ๋์ด.
ํนํ ํ์
์์ ์ฑ(Type Safety)์ด๋ ์ต์
๋(Optional) ๊ฐ๋
์ ์ง์ง ํ์ ์ด์๋๋ฐ, ๋ฐํ์์์ ํฐ์ง๋ nil ๊ด๋ จ ํฌ๋์๋ฅผ ์ปดํ์ผ ํ์์ ์ก์๋ผ ์ ์๊ฒ ๋๊ฑฐ๋ . ์ด๊ฒ ์ผ๋ง๋ ํฐ ๋ณํ๋๋ฉด... ์์ ์ ์ฑ ๋ฐฐํฌํ๊ณ ๋์ "์ด ์ ํฐ์ง์ง?" ํ๋ ๊ฒฝ์ฐ๊ฐ ์ง์ง ๋ง์๋๋ฐ ๊ทธ๊ฒ ํ ์ค์ด๋ ๊ฑฐ์ผ ๐ค
๐ ๏ธ Xcode โ Apple์ ํตํฉ ๊ฐ๋ฐ ํ๊ฒฝ(IDE) ์์ ํด๋ถ
Swift ์๊ธฐํ๋ฉด์ Xcode ๋นผ๋ฉด ์ญ์ญํ์ง ใ
ใ
ใ
Xcode๋ Apple์ด ๋ง๋ ๊ณต์ IDE์ธ๋ฐ, macOS์์๋ง ๋์๊ฐ๊ณ App Store์์ ๋ฌด๋ฃ๋ก ๋ฐ์ ์ ์์ด.
๊ทผ๋ฐ ์ด๊ฒ ๋จ์ํ ์ฝ๋ ์๋ํฐ๊ฐ ์๋๋ผ ์ง์ง ์ฌ์ธ์ ๊ฐ๋ฐ ํ๋ซํผ์ด๊ฑฐ๋ .
๐ฑ Xcode์ ํต์ฌ ๊ธฐ๋ฅ๋ค โ ์ด๊ฑฐ ๋ค ์๋ฉด ์ง์ง ๊ณ ์
Swift, Objective-C, C, C++ ๋ฑ ๋ค์ํ ์ธ์ด ์ง์. ์ฝ๋ ์๋์์ฑ(Code Completion)์ด ์ง์ง ๊ฐ๋ ฅํ๋ฐ, 2023๋ ๋ถํฐ Predictive Code Completion ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋๋ฉด์ AI ๊ธฐ๋ฐ ์ฝ๋ ์ ์๊น์ง ํด์ค. ๊ทธ๋ฅ ํ์ดํํ๋ค ๋ณด๋ฉด "์ด ์ด๊ฑฐ ๋ง๋ค?" ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ก์ด ใ ใ
์์ ์ Interface Builder(IB)๋ก ๋๋๊ทธ์ค๋๋กญ์ผ๋ก UI ๋ง๋ค์๋๋ฐ, SwiftUI ๋์ค๋ฉด์ Canvas Preview๊ฐ ์๊ฒผ์ด. ์ฝ๋ ์น๋ฉด ์์์ ์ค์๊ฐ์ผ๋ก UI๊ฐ ๋ฐ๋๋ ๊ฑฐ ๋ณด์ฌ์ค. ์ด๊ฑฐ ์ฒ์ ๋ดค์ ๋ ์ง์ง "์ค ์ด๊ฒ ๋๋ค?!" ํ์ ๐ฒ
์ฑ๋ฅ ๋ถ์ ๋๊ตฌ์ธ๋ฐ ์ด๊ฑฐ ์ ๋๋ก ์ธ ์ค ์๋ฉด ์ฑ ์ต์ ํ๊ฐ ์์ ๋ฌ๋ผ์ง. CPU ์ฌ์ฉ๋, ๋ฉ๋ชจ๋ฆฌ ๋์, ๋คํธ์ํฌ ํธ๋ํฝ, ์๋์ง ์๋น๊น์ง ๋ค ๋ถ์ ๊ฐ๋ฅ. Time Profiler, Allocations, Leaks ๋ฑ 30๊ฐ ์ด์์ ๋ถ์ ๋๊ตฌ ๋ด์ฅ.
์ค์ ๊ธฐ๊ธฐ ์์ด๋ iPhone, iPad, Apple Watch, Apple TV, Vision Pro๊น์ง ์๋ฎฌ๋ ์ด์ ๊ฐ๋ฅ. ๊ทผ๋ฐ ์ง์ง ๊ธฐ๊ธฐ๋์ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ์์ผ๋๊น ์ต์ข ํ ์คํธ๋ ์ค๊ธฐ๊ธฐ๋ก ํด์ผ ํด. ํนํ ์นด๋ฉ๋ผ, ๋ธ๋ฃจํฌ์ค, NFC ๊ฐ์ ํ๋์จ์ด ๊ธฐ๋ฅ์ ์๋ฎฌ๋ ์ดํฐ์์ ์ ๋จ.
๐๏ธ Swift Package Manager โ ์์กด์ฑ ๊ด๋ฆฌ์ ์งํ
์์ ์ iOS ๊ฐ๋ฐํ๋ฉด CocoaPods๋ Carthage ์จ์ผ ํ๋๋ฐ, ์ด๊ฒ ์ค์ ์ด ์ข ๋ณต์กํ๊ฑฐ๋ ใ
ใ
๊ทผ๋ฐ Swift Package Manager(SPM)๊ฐ Xcode์ ์์ ํตํฉ๋๋ฉด์ ๊ฒ์ ์ฒด์ธ์ ๊ฐ ๋์ด!
// Package.swift ์์
// Swift Package Manager ์ค์ ํ์ผ
import PackageDescription
let package = Package(
name: "MyAwesomeApp",
platforms: [
.iOS(.v16),
.macOS(.v13)
],
dependencies: [
// GitHub URL๋ก ํจํค์ง ์ถ๊ฐ
.package(url: "https://github.com/Alamofire/Alamofire", from: "5.8.0"),
.package(url: "https://github.com/onevcat/Kingfisher", from: "7.0.0")
],
targets: [
.target(
name: "MyAwesomeApp",
dependencies: ["Alamofire", "Kingfisher"]
)
]
)
Xcode์์ ๊ทธ๋ฅ File โ Add Package Dependencies ํ๋ฉด GitHub URL ๋ถ์ฌ๋ฃ๊ธฐ๋ง ํด๋ ํจํค์ง ์ถ๊ฐ ์๋ฃ ใ
ใ
์ด๊ฒ ์ผ๋ง๋ ํธํ๋๋ฉด... CocoaPods ์ธ ๋๋ ํฐ๋ฏธ๋์์ pod install ํ๊ณ , Podfile ์์ ํ๊ณ , .xcworkspace ์ด๊ณ ... ์ด๋ฐ ๊ณผ์ ์ด ์์๋๋ฐ ์ด์ ๊ทธ๋ฅ ํด๋ฆญ ๋ช ๋ฒ์ด๋ฉด ๋จ ๐
SPM: Apple ๊ณต์ ์ง์, Xcode ์์ ํตํฉ, ์ค์ ๊ฐ๋จ โ
CocoaPods: ๊ฐ์ฅ ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ง์, Ruby ๊ธฐ๋ฐ, ์ค์ ๋ณต์ก โ ๏ธ
Carthage: ๋ถ์ฐํ ๊ด๋ฆฌ, ๋น๋ ์๋ ๋น ๋ฆ, ์ฌ์ฉ์ ๊ฐ์ ์ถ์ธ ๐
ํ์ฌ ํธ๋ ๋๋ SPM์ผ๋ก ํตํฉ๋๋ ์ค!
๐จ SwiftUI โ ์ ์ธํ UI์ ํ๋ช
2019๋
SwiftUI ๋ฐํ๋ ์ง์ง Apple ๊ฐ๋ฐ ์ญ์ฌ์์ ํ ํ์ ๊ทธ์ ์ฌ๊ฑด์ด์ผ.
๊ธฐ์กด UIKit์ ๋ช
๋ นํ(Imperative) ๋ฐฉ์์ด์๋๋ฐ, SwiftUI๋ ์ ์ธํ(Declarative) ๋ฐฉ์์ด๊ฑฐ๋ .
// UIKit ๋ฐฉ์ (๋ช
๋ นํ) - "์ด๋ป๊ฒ ํ ์ง" ์ง์ ์ง์
let label = UILabel()
label.text = "์๋
ํ์ธ์"
label.textColor = .blue
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
// SwiftUI ๋ฐฉ์ (์ ์ธํ) - "๋ฌด์์ ์ํ๋์ง" ์ ์ธ
Text("์๋
ํ์ธ์")
.foregroundColor(.blue)
.font(.system(size: 20, weight: .bold))
๋ด๋ด ์ด ์ฐจ์ด ใ
ใ
ใ
์ฝ๋ ์์ด ์์ ๋ค๋ฅด์ง?
SwiftUI์ ํต์ฌ ๊ฐ๋
๋ค์ ์ข ๋ ํ๊ณ ๋ค์ด ๋ณผ๊ฒ ๐
โก SwiftUI ํต์ฌ ๊ฐ๋ 5๊ฐ์ง
๋ชจ๋ UI ์์๋
View ํ๋กํ ์ฝ์ ๋ฐ๋ฆ. body ํ๋กํผํฐ์ UI๋ฅผ ์ ์ธํ๋ฉด ๋. ๊ตฌ์กฐ์ฒด(struct) ๊ธฐ๋ฐ์ด๋ผ ๊ฐ ํ์
์ผ๋ก ๋์ํด์ ์ฑ๋ฅ๋ ์ข์.
@State๋ ๋ทฐ ๋ด๋ถ ์ํ ๊ด๋ฆฌ, @Binding์ ๋ถ๋ชจ-์์ ๋ทฐ ๊ฐ ๋ฐ์ดํฐ ๊ณต์ . ์ํ๊ฐ ๋ฐ๋๋ฉด ์๋์ผ๋ก UI๊ฐ ์
๋ฐ์ดํธ๋จ. ์ด๊ฒ ์ง์ง ํ์ ์ธ ๊ฒ, ์์ ์ reloadData() ์ด๋ฐ ๊ฑฐ ์ง์ ํธ์ถํด์ผ ํ๊ฑฐ๋ .
๋ทฐ๋ชจ๋ธ ํจํด ๊ตฌํ์ ์ฌ์ฉ.
@Published ํ๋กํผํฐ๊ฐ ๋ฐ๋๋ฉด ํด๋น ๋ทฐ๋ชจ๋ธ์ ๊ตฌ๋
ํ๋ ๋ชจ๋ ๋ทฐ๊ฐ ์๋ ์
๋ฐ์ดํธ. MVVM ์ํคํ
์ฒ์ ์ฐฐ๋ก๊ถํฉ ๐ค
์ฑ ์ ์ฒด์์ ๊ณต์ ๋๋ ๋ฐ์ดํฐ๋ฅผ ํ๊ฒฝ(Environment)์ผ๋ก ์ฃผ์ . ๋คํฌ๋ชจ๋, ํฐํธ ํฌ๊ธฐ, ๋ก์ผ์ผ ๊ฐ์ ์์คํ ์ค์ ๋ Environment๋ก ์ ๊ทผ ๊ฐ๋ฅ. ์ ์ญ ์ํ ๊ด๋ฆฌ๊ฐ ํจ์ฌ ๊น๋ํด์ง.
.padding(), .background(), .cornerRadius() ๊ฐ์ modifier๋ฅผ ์ฒด์ด๋ํด์ ์คํ์ผ ์ ์ฉ. ์์๊ฐ ์ค์ํ๋ฐ, ์ด๊ฒ ์ฒ์์ ํท๊ฐ๋ฆด ์ ์์ด. ์๋ฅผ ๋ค์ด .padding() ๋จผ์ ํ๊ณ .background() ํ๋ฉด ํจ๋ฉ ์์ญ๊น์ง ๋ฐฐ๊ฒฝ์์ด ์ ์ฉ๋จ.
โก Swift Concurrency โ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ ์๋
Swift 5.5์์ ๋์
๋ async/await๋ ์ง์ง ๊ฐ๋ฐ์๋ค ์ถ์ ์ง์ ์ฌ๋ ค์ค ๊ธฐ๋ฅ์ด์ผ ใ
ใ
ใ
์์ ์ ๋น๋๊ธฐ ์ฝ๋ ์ง๋ฉด ์ฝ๋ฐฑ ์ง์ฅ(Callback Hell)์ด ํผ์ณ์ง๊ฑฐ๋ ...
// ์์ ๋ฐฉ์ - ์ฝ๋ฐฑ ์ง์ฅ ๐ฑ
func fetchUserData(completion: @escaping (User?) -> Void) {
networkManager.fetchUser { user in
guard let user = user else {
completion(nil)
return
}
networkManager.fetchPosts(for: user.id) { posts in
networkManager.fetchComments(for: posts) { comments in
// ์ด๊ฒ ๊ณ์ ์ค์ฒฉ๋๋ฉด... ๐ต
completion(user)
}
}
}
}
// async/await ๋ฐฉ์ - ๊น๋! ๐
func fetchUserData() async throws -> User {
let user = try await networkManager.fetchUser()
let posts = try await networkManager.fetchPosts(for: user.id)
let comments = try await networkManager.fetchComments(for: posts)
return user
}
์ด ์ฐจ์ด ๋ณด์ด์ง? ์ฝ๋๊ฐ ์์์ ์๋๋ก ์์๋๋ก ์ฝํ๋ ๊ฒ ์ผ๋ง๋ ํธํ์ง ใ
ใ
Swift Concurrency์ ํต์ฌ ๊ฐ๋
๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ:
| ๊ฐ๋ | ์ค๋ช | ์ฌ์ฉ ์์ |
|---|---|---|
| async/await | ๋น๋๊ธฐ ํจ์ ์ ์ ๋ฐ ํธ์ถ | ๋คํธ์ํฌ ์์ฒญ, ํ์ผ I/O |
| Task | ๋น๋๊ธฐ ์์ ๋จ์ ์์ฑ | ๋ทฐ์์ ๋น๋๊ธฐ ์์ ์์ |
| Actor | ๋ฐ์ดํฐ ๋ ์ด์ค ๋ฐฉ์ง ํ์ | ๊ณต์ ์ํ ์์ ํ๊ฒ ๊ด๋ฆฌ |
| async let | ๋ณ๋ ฌ ๋น๋๊ธฐ ์์ | ์ฌ๋ฌ API ๋์ ํธ์ถ |
| AsyncStream | ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ | ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ |
Swift 6.0์์๋ Strict Concurrency Checking์ด ๊ธฐ๋ณธ ํ์ฑํ๋จ. ์ปดํ์ผ๋ฌ๊ฐ ๋ฐ์ดํฐ ๋ ์ด์ค ๊ฐ๋ฅ์ฑ์ ์ปดํ์ผ ํ์์ ์ก์์ค. ์ด๊ฒ ํ์ฑํ๋๋ฉด ๊ธฐ์กด ์ฝ๋์์ ๊ฒฝ๊ณ /์๋ฌ๊ฐ ๋ง์ด ๋์ฌ ์ ์๋๋ฐ, ์ด๊ฑธ ๋ค ๊ณ ์น๋ฉด ์ง์ง ์์ ํ ๋์์ฑ ์ฝ๋๊ฐ ์์ฑ๋จ ๐ช
๐ Apple ์ํ๊ณ ํฌ๋ก์ค ํ๋ซํผ ์ ๋ต
Apple ์ํ๊ณ์ ์ง์ง ๊ฐ์ ์ ํ๋์ ์ฝ๋๋ก ์ฌ๋ฌ ํ๋ซํผ ์ง์์ด ๊ฐ๋ฅํ๋ค๋ ๊ฑฐ์ผ.
์ด๊ฒ ์ด๋ป๊ฒ ๊ฐ๋ฅํ์ง ์ดํด๋ณด์ ๐
๐ Catalyst & Mac Idiom โ iPad ์ฑ์ Mac์ผ๋ก
Mac Catalyst๋ iPad ์ฑ์ macOS ์ฑ์ผ๋ก ๋ณํํด์ฃผ๋ ๊ธฐ์ ์ด์ผ.
Xcode์์ ์ฒดํฌ๋ฐ์ค ํ๋๋ง ์ผ๋ฉด iPad ์ฑ์ด Mac์์๋ ๋์๊ฐ๋ ๊ฑฐ ใ
ใ
๋ฌผ๋ก UI ์ต์ ํ๋ ๋ณ๋๋ก ํด์ผ ํ์ง๋ง, ๊ธฐ๋ณธ์ ์ธ ๋์์ ๋ฐ๋ก ๋จ.
๋ ๋์๊ฐ์ SwiftUI์ ํ๋ซํผ ์กฐ๊ฑด๋ถ ์ฝ๋๋ฅผ ์ฐ๋ฉด ํ๋์ ์ฝ๋๋ฒ ์ด์ค๋ก ํ๋ซํผ๋ณ ์ต์ ํ๋ UI๋ฅผ ์ ๊ณตํ ์ ์์ด:
// ํ๋ซํผ๋ณ ์กฐ๊ฑด๋ถ UI
struct ContentView: View {
var body: some View {
#if os(iOS)
// iOS ์ ์ฉ UI
NavigationStack {
List { /* ... */ }
}
#elseif os(macOS)
// macOS ์ ์ฉ UI
NavigationSplitView {
List { /* ... */ }
} detail: {
Text("ํญ๋ชฉ์ ์ ํํ์ธ์")
}
#elseif os(watchOS)
// watchOS ์ ์ฉ UI
List { /* ... */ }
#endif
}
}
๐ฅฝ visionOS โ ๊ณต๊ฐ ์ปดํจํ ์ ์์
2024๋
Apple Vision Pro ์ถ์์ ํจ๊ป visionOS๊ฐ ๋ฑ์ฅํ์ด.
์ด๊ฒ ์ง์ง ์๋ก์ด ํจ๋ฌ๋ค์์ธ ๊ฒ, 2D ์ฑ๋ ๊ทธ๋ฅ ๊ณต๊ฐ์ ๋์ธ ์ ์๊ณ , RealityKit์ผ๋ก 3D ์ฝํ
์ธ ๋ ๋ง๋ค ์ ์๊ฑฐ๋ .
SwiftUI๋ก ๋ง๋ ๊ธฐ์กด ์ฑ์ visionOS์์ Compatibility Mode๋ก ๋ฐ๋ก ์คํ ๊ฐ๋ฅํ๊ณ , ๋ ๋์๊ฐ Volumetric Window๋ Immersive Space๋ฅผ ํ์ฉํ๋ฉด ์์ ํ ๊ณต๊ฐ ์ปดํจํ
์ฑ์ ๋ง๋ค ์ ์์ด.
โข Window: ๊ธฐ์กด 2D ์ฑ์ฒ๋ผ ํ๋ฉด ์ฐฝ
โข Volume: 3D ์ฝํ ์ธ ๋ฅผ ๋ด๋ ๋ฐ์คํ ๊ณต๊ฐ
โข Immersive Space: ์์ ํ ๋ชฐ์ ํ ํ๊ฒฝ (AR/VR)
โข RealityKit: 3D ๋ ๋๋ง ํ๋ ์์ํฌ
โข Reality Composer Pro: 3D ์์ ํธ์ง ๋๊ตฌ (Xcode ํตํฉ)
๐ค AI ํตํฉ โ Xcode Intelligence์ ๋ฑ์ฅ
2024๋
Apple์ด ๋ฐํํ Apple Intelligence์ ํจ๊ป Xcode๋ AI ๊ธฐ๋ฅ์ด ๊ฐํ๋์ด.
์ด๊ฒ ์ง์ง ๊ฐ๋ฐ ์์ฐ์ฑ์ ๋ฐ๊ฟ๋๊ณ ์๋๋ฐ ใ
ใ
Xcode 16๋ถํฐ on-device AI ๋ชจ๋ธ์ด ์ฝ๋ ์ปจํ ์คํธ๋ฅผ ์ดํดํ๊ณ ๋ค์ ์ฝ๋๋ฅผ ์์ธกํด์ ์ ์ํด์ค. GitHub Copilot ๊ฐ์ ์ธ๋ถ ๋๊ตฌ ์์ด๋ Apple ์์ฒด AI๋ก ์ฝ๋ ์๋์์ฑ์ด ๊ฐ๋ฅํด์ง ๊ฑฐ์ผ. ๊ฐ์ธ์ ๋ณด ๋ณดํธ ์ธก๋ฉด์์๋ ์ฝ๋๊ฐ ์ธ๋ถ ์๋ฒ๋ก ์ ๋๊ฐ๋ ๊ฒ ์ฅ์ ๐
Xcode 16์์ ์๋ก์ด Swift Testing ํ๋ ์์ํฌ๊ฐ ๋์ ๋จ. ๊ธฐ์กด XCTest๋ณด๋ค ํจ์ฌ ํ๋์ ์ธ ๋ฌธ๋ฒ์ผ๋ก ํ ์คํธ ์์ฑ ๊ฐ๋ฅ.
@Test ๋งคํฌ๋ก๋ก ํ
์คํธ ํจ์ ์ ์ํ๊ณ , #expect๋ก ๊ฒ์ฆํ๋ ๋ฐฉ์์ด ํจ์ฌ ์ง๊ด์ ์.
// ์๋ก์ด Swift Testing ํ๋ ์์ํฌ
import Testing
@Test("์ฌ์ฉ์ ๋ก๊ทธ์ธ ํ
์คํธ")
func testUserLogin() async throws {
let authService = AuthService()
let result = try await authService.login(
email: "test@example.com",
password: "password123"
)
#expect(result.isSuccess == true)
#expect(result.user?.email == "test@example.com")
}
// ํ๋ผ๋ฏธํฐํ๋ ํ
์คํธ
@Test("๋ค์ํ ์
๋ ฅ๊ฐ ๊ฒ์ฆ", arguments: [1, 2, 3, 4, 5])
func testPositiveNumbers(number: Int) {
#expect(number > 0)
}
๐ฆ Swift Macros โ ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ ์งํ
Swift 5.9์์ ๋์
๋ Swift Macros๋ ์ง์ง ๊ณ ๊ธ ๊ธฐ๋ฅ์ธ๋ฐ, ์ด๊ฒ ๋ญ์ง ์๋ฉด "์ค ์ด๋ฐ ๊ฒ๋ ๋๋ค" ํ๊ฒ ๋จ ใ
ใ
๋งคํฌ๋ก๋ ์ปดํ์ผ ํ์์ ์ฝ๋๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ณํํ๋ ๊ธฐ๋ฅ์ด์ผ.
// @Observable ๋งคํฌ๋ก ์ฌ์ฉ ์์ (Swift 5.9+)
import Observation
@Observable
class UserViewModel {
var name: String = ""
var email: String = ""
var isLoggedIn: Bool = false
// @Observable ๋งคํฌ๋ก๊ฐ ์๋์ผ๋ก
// ๋ณ๊ฒฝ ๊ฐ์ง ์ฝ๋๋ฅผ ์์ฑํด์ค!
}
// SwiftUI์์ ์ฌ์ฉ
struct ProfileView: View {
@State private var viewModel = UserViewModel()
var body: some View {
VStack {
Text(viewModel.name)
Text(viewModel.email)
}
// @Observable์ด๋ฉด @ObservedObject ์์ด๋ ์๋ ์
๋ฐ์ดํธ!
}
}
@Observable ๋งคํฌ๋ก๋ Apple์ด ์ ๊ณตํ๋ ๋ํ์ ์ธ ๋งคํฌ๋ก์ธ๋ฐ, ๊ธฐ์กด์ ObservableObject + @Published ์กฐํฉ์ผ๋ก ํด์ผ ํ๋ ๊ฑธ ํจ์ฌ ๊ฐ๋จํ๊ฒ ๋ง๋ค์ด์ค.
์ง์ ์ปค์คํ
๋งคํฌ๋ก๋ ๋ง๋ค ์ ์๋๋ฐ, ์ด๊ฑด ์ข ๊ณ ๊ธ ์ฃผ์ ๋ผ ๋์ค์ ๋ฐ๋ก ๊น๊ฒ ํ๋ด์ผ ํด ๐
๐๏ธ Swift ์ํคํ ์ฒ ํจํด โ ์ด๋ค ๊ฑธ ์จ์ผ ํ ๊น?
์ฑ ๊ท๋ชจ๊ฐ ์ปค์ง๋ฉด ์ํคํ ์ฒ ์ ํ์ด ์ง์ง ์ค์ํด์ ธ. Apple ์ํ๊ณ์์ ์ฃผ๋ก ์ฐ์ด๋ ํจํด๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ ๐๏ธ
| ํจํด | ํน์ง | ์ ํฉํ ์ํฉ |
|---|---|---|
| MVC | UIKit ๊ธฐ๋ณธ ํจํด. ๊ฐ๋จํ์ง๋ง Massive VC ๋ฌธ์ | ์๊ท๋ชจ UIKit ์ฑ |
| MVVM | SwiftUI์ ์ฐฐ๋ก. ViewModel์ด ๋น์ฆ๋์ค ๋ก์ง ๋ด๋น | SwiftUI ์ฑ (๊ฐ์ฅ ์ผ๋ฐ์ ) |
| TCA | ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ. ํ ์คํธ ์ฉ์ด. ํ์ต ๊ณก์ ๋์ | ๋ณต์กํ ์ํ ๊ด๋ฆฌ ํ์ ์ |
| Clean Architecture | ๋ ์ด์ด ๋ถ๋ฆฌ. ์ ์ง๋ณด์์ฑ ์ต๊ณ . ๋ณด์ผ๋ฌํ๋ ์ดํธ ๋ง์ | ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ์ฑ |
| VIPER | 5๊ฐ ๋ ์ด์ด ๋ถ๋ฆฌ. ํ ์คํธ ์ฉ์ด. ๋ณต์ก๋ ๋์ | ๋ํ ํ ๊ฐ๋ฐ |
์์ฆ ํธ๋ ๋๋ SwiftUI + MVVM + Swift Concurrency ์กฐํฉ์ด ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๊ณ , ๋ณต์กํ ์ฑ์ TCA(The Composable Architecture)๋ฅผ ์ ํํ๋ ๊ฒฝ์ฐ๋ ๋๊ณ ์์ด.
TCA๋ Point-Free์์ ๋ง๋ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ๋ฐ, ํ์ต ๊ณก์ ์ด ์ข ์์ง๋ง ํ ๋ฒ ์ตํ๋ฉด ์ง์ง ๊ฐ๋ ฅํจ ๐ช
๐ฎ Swift์ Apple IDE์ ๋ฏธ๋ ๋ฐฉํฅ
์ ์ด์ ์ง์ง ํฅ๋ฏธ๋ก์ด ๋ถ๋ถ โ ์์ผ๋ก ์ด๋ป๊ฒ ๋ ๊ฒ ๊ฐ๋ ใ
ใ
Apple์ด ๊ณต๊ฐํ ๋ก๋๋งต๊ณผ ์ปค๋ฎค๋ํฐ ํธ๋ ๋๋ฅผ ๋ฐํ์ผ๋ก ๋ถ์ํด๋ณผ๊ฒ ๐ญ
๐ Swift ์ธ์ด์ ๋ฐ์ ๋ฐฉํฅ
Vapor, Hummingbird ๊ฐ์ ํ๋ ์์ํฌ๋ก ์๋ฒ ๊ฐ๋ฐ๋ Swift๋ก ๊ฐ๋ฅํด. Apple์ด Swift Foundation์ ์คํ์์ค๋ก ๊ณต๊ฐํ๋ฉด์ Linux ์ง์์ด ๊ฐํ๋๊ณ , AWS Lambda์์ Swift ๋ฐํ์๋ ์ง์ํจ. ํ๋ก ํธ์๋(iOS)๋ถํฐ ๋ฐฑ์๋๊น์ง Swift ํ๋๋ก ํ์คํ ๊ฐ๋ฐํ๋ ์๋๊ฐ ์ค๊ณ ์์ด ๐
Swift๋ฅผ WebAssembly(WASM)๋ก ์ปดํ์ผํ๋ ์์ ์ด ์งํ ์ค์ด์ผ. ์ด๊ฒ ์์ฑ๋๋ฉด Swift ์ฝ๋๊ฐ ์น ๋ธ๋ผ์ฐ์ ์์๋ ๋์๊ฐ ์ ์๊ฒ ๋จ. ์์ง ์คํ์ ๋จ๊ณ์ง๋ง Swift ์ํ๊ณ๊ฐ ์น์ผ๋ก๋ ํ์ฅ๋ ๊ฐ๋ฅ์ฑ์ด ์์ด.
Swift 5.9๋ถํฐ ์๋ฒ ๋๋ ์์คํ ์ง์์ด ์์๋จ. ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ๋ ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ์์๋ Swift๋ฅผ ์ธ ์ ์๊ฒ ๋๋ ๊ฑฐ์ผ. Apple Silicon์ ํ์ฅ๊ณผ ํจ๊ป IoT ๋ถ์ผ์์๋ Swift๊ฐ ํ์ฉ๋ ์ ์์ด.
๐ ๏ธ Xcode์ ๋ฏธ๋
Apple Intelligence์ Xcode์ ํตํฉ์ด ๋ ๊น์ด์ง ๊ฑฐ์ผ. ๋จ์ ์ฝ๋ ์์ฑ์ ๋์ด์ ๋ฒ๊ทธ ์๋ ์์ , ๋ฆฌํฉํ ๋ง ์ ์, ํ ์คํธ ์๋ ์์ฑ๊น์ง AI๊ฐ ๋์์ฃผ๋ ๋ฐฉํฅ์ผ๋ก ๋ฐ์ ํ ๊ฒ์ผ๋ก ์์๋จ. GitHub Copilot, Cursor ๊ฐ์ ์ธ๋ถ ๋๊ตฌ๋ค๊ณผ์ ๊ฒฝ์๋ ์น์ดํด์ง๊ณ ์์ด.
ํ์ฌ Xcode๋ macOS์์๋ง ๋์๊ฐ๋๋ฐ, ์ด๊ฒ ๊ฐ๋ฐ์๋คํํ ์ง์ ์ฅ๋ฒฝ์ด ๋๊ธฐ๋ ํด. Swift Playgrounds๊ฐ iPad์์ ๋๋ ๊ฒ์ฒ๋ผ, ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ Xcode ํ๊ฒฝ์ด ๋์ฌ ๊ฐ๋ฅ์ฑ๋ ์์ด. ์ค์ ๋ก GitHub Codespaces์์ Swift ๊ฐ๋ฐ์ด ๊ฐ๋ฅํ๊ธด ํ๋ฐ, ์์ง Xcode ์์ค์ ์๋.
SwiftUI๊ฐ ๊ณ์ ๋ฐ์ ํ๋ฉด์ ํ๋ซํผ ๊ฐ ์ฝ๋ ๊ณต์ ์จ์ด ๋์์ง๊ณ ์์ด. ํนํ visionOS ์ํ๊ณ๊ฐ ์ฑ์ํด์ง๋ฉด์ ๊ณต๊ฐ ์ปดํจํ ์ฑ ๊ฐ๋ฐ ๋๊ตฌ๋ ๋ ๊ฐํ๋ ๊ฒ์ผ๋ก ๋ณด์. Reality Composer Pro๊ฐ Xcode์ ๋ ๊น์ด ํตํฉ๋๋ ๋ฐฉํฅ์ผ๋ก ๊ฐ ๊ฒ ๊ฐ์.
๐ ์ค์ ๊ฐ๋ฐ ํ โ ์ด๊ฒ๋ง ์๋ฉด ์ค๊ธ ์ด์
์ด๋ก ๋ง ์๋ฉด ๋ญํด, ์ค์ ์์ ์จ๋จน์ด์ผ์ง ใ
ใ
ํ์
์์ ์ง์ง ์ ์ฉํ ํ๋ค์ ๋ชจ์๋ดค์ด ๐
Cmd + Shift + O: ํ์ผ ๋น ๋ฅธ ์ด๊ธฐ (์ง์ง ์์ฃผ ์)Cmd + Shift + F: ํ๋ก์ ํธ ์ ์ฒด ๊ฒ์Ctrl + I: ์ฝ๋ ์๋ ๋ค์ฌ์ฐ๊ธฐCmd + /: ์ฃผ์ ํ ๊ธCmd + B: ๋น๋Cmd + R: ์คํCmd + U: ํ
์คํธ ์คํ์ด๊ฑฐ ์ธ์ฐ๋ฉด ๊ฐ๋ฐ ์๋๊ฐ ์ง์ง ๋ฌ๋ผ์ง โก
SwiftUI Preview๋ ๊ทธ๋ฅ UI ํ์ธ์ฉ์ด ์๋์ผ.
#Preview ๋งคํฌ๋ก๋ก ๋ค์ํ ์ํ๋ฅผ ๋ฏธ๋ฆฌ ๋ณผ ์ ์์ด. ๋คํฌ๋ชจ๋, ๋ค์ํ ๊ธฐ๊ธฐ ํฌ๊ธฐ, ์ ๊ทผ์ฑ ํฐํธ ํฌ๊ธฐ ๋ฑ์ Preview์์ ๋ฐ๋ก ํ์ธํ๋ฉด ์ค๊ธฐ๊ธฐ ํ
์คํธ ํ์๊ฐ ํ ์ค์ด๋ฆ.
์ฑ์ด ๋๋ ค์ง๊ฑฐ๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๊ณ์ ์ฌ๋ผ๊ฐ๋ค๋ฉด Instruments์ Leaks ๋๊ตฌ๋ฅผ ์จ๋ด. ํนํ ํด๋ก์ ์์
[weak self] ์ ์ฐ๋ฉด ์ํ ์ฐธ์กฐ(Retain Cycle)๊ฐ ์๊ฒจ์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ์ํจ. ์ด๊ฑฐ ์ก๋ ๊ฒ ์ง์ง ์ค์ํด.
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ๋ฉด์ ๋์์ ์ฑ์์ ํ ์คํธํ๊ณ ์ถ์ ๋, ๋ก์ปฌ ํจํค์ง๋ก ์ถ๊ฐํ๋ฉด ๋จ. Xcode์์ ํจํค์ง ์ถ๊ฐํ ๋ GitHub URL ๋์ ๋ก์ปฌ ํด๋ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋ฉด ๋ผ. ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ๋ก ๋ฐ์๋์ด์ ๊ฐ๋ฐ์ด ํจ์ฌ ํธํจ.
ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด ๋น๋ ์๊ฐ์ด ๊ธธ์ด์ง๋๋ฐ, ์ด๊ฑธ ์ค์ด๋ ๋ฐฉ๋ฒ๋ค์ด ์์ด:
โข ๋ชจ๋ํ(Modularization)๋ก ์ฆ๋ถ ๋น๋ ํ์ฉ
โข
-Onone ์ต์ ํ ๋ ๋ฒจ๋ก ๋๋ฒ๊ทธ ๋น๋ ์๋ ํฅ์โข ํ์ ์ถ๋ก ์ด ๋ณต์กํ ์ฝ๋๋ ๋ช ์์ ํ์ ์ ์ธ
โข Swift Package๋ก ์์กด์ฑ ๋ถ๋ฆฌํ๋ฉด ์บ์ ํ์ฉ ๊ฐ๋ฅ
๐ฏ ์ ๋ฆฌ โ Apple ์ํ๊ณ ๊ฐ๋ฐ์๋ก ์ฑ์ฅํ๋ ๋ก๋๋งต
์ ์ด์ ์ ์ฒด์ ์ธ ๊ทธ๋ฆผ์ด ๊ทธ๋ ค์ก์ง? ใ
ใ
๋ง์ง๋ง์ผ๋ก Apple ์ํ๊ณ ๊ฐ๋ฐ์๋ก ์ฑ์ฅํ๋ ๋จ๊ณ๋ณ ๋ก๋๋งต์ ์ ๋ฆฌํด์ค๊ฒ ๐บ๏ธ
Swift ๊ธฐ๋ณธ ๋ฌธ๋ฒ (๋ณ์, ํจ์, ํด๋ก์ , ํ๋กํ ์ฝ, ์ ๋ค๋ฆญ)
Xcode ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
UIKit ๋๋ SwiftUI ๊ธฐ์ด
Auto Layout / SwiftUI Layout ์ดํด
๋คํธ์ํน (URLSession, async/await)
๋ฐ์ดํฐ ์ ์ฅ (UserDefaults, CoreData, SwiftData)
MVVM ์ํคํ ์ฒ ํจํด ์ ์ฉ
Git ๋ฒ์ ๊ด๋ฆฌ + Xcode ํตํฉ
Swift Concurrency ์ฌํ (Actor, AsyncStream)
Swift Package Manager ํ์ฉ
Unit Test / UI Test ์์ฑ
Instruments ์ฑ๋ฅ ๋ถ์
App Store ๋ฐฐํฌ ํ๋ก์ธ์ค
Swift Macros ์ปค์คํ ๊ตฌํ
TCA ๋๋ Clean Architecture ์ ์ฉ
๋ฉํฐ ํ๋ซํผ ์ฑ ๊ฐ๋ฐ (iOS + macOS + watchOS)
Swift on Server ๊ฒฝํ
์คํ์์ค ๊ธฐ์ฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ
Apple ์ํ๊ณ์ Swift๋ ์ ๋ง ๋น ๋ฅด๊ฒ ๋ฐ์ ํ๊ณ ์์ด. 2014๋ ์ ํ์ด๋ ์ธ์ด๊ฐ 10๋ ๋ง์ iOS, macOS, watchOS, tvOS, visionOS๋ฅผ ์์ฐ๋ฅด๊ณ , ์๋ฒ์ ์๋ฒ ๋๋ ์์คํ ๊น์ง ๋๋ณด๊ณ ์๋ค๋ ๊ฒ ์ง์ง ๋๋จํ์ง ์์? ใ ใ
Xcode๋ AI ๊ธฐ๋ฅ์ด ๊ฐํ๋๋ฉด์ ๊ฐ๋ฐ ์์ฐ์ฑ์ด ๊ณ์ ์ฌ๋ผ๊ฐ๊ณ ์๊ณ , SwiftUI๋ ์ ์ธํ UI์ ํ์ค์ผ๋ก ์๋ฆฌ์ก์๊ฐ๊ณ ์์ด.
์ค์ํ ๊ฑด ๊ธฐ์ด๋ฅผ ํํํ ํ๊ณ , ๋ณํ์ ์ ์ํ๋ ๋ฅ๋ ฅ์ ๊ธฐ๋ฅด๋ ๊ฑฐ์ผ. Swift ์ธ์ด ์์ฒด์ ์ฒ ํ โ ์์ ์ฑ, ์๋, ํํ๋ ฅ โ ์ ์ดํดํ๋ฉด ์๋ก์ด ๊ธฐ๋ฅ์ด ๋์๋ ๊ธ๋ฐฉ ์ ์ํ ์ ์๊ฑฐ๋ ๐ช
์, ์ด์ Xcode ์ผ๊ณ ์ฝ๋ฉ ์์ํด๋ณผ๊น? ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.