Section 16/171 menit
16. Real Use Cases
16. Real Use Cases
Use Case 1: Modular App dengan Feature Packages
Struktur app dengan 3 feature module + 2 core module.
swift
// Modules/CoreNetworking/Package.swift
// swift-tools-version:5.10
import PackageDescription
let package = Package(
name: "CoreNetworking",
platforms: [.iOS(.v16)],
products: [
.library(name: "CoreNetworking", targets: ["CoreNetworking"]),
],
targets: [
.target(name: "CoreNetworking"),
.testTarget(name: "CoreNetworkingTests", dependencies: ["CoreNetworking"]),
]
)
swift
// Modules/CoreNetworking/Sources/CoreNetworking/HTTPClient.swift
import Foundation
public actor HTTPClient {
private let session: URLSession
public init(session: URLSession = .shared) {
self.session = session
}
public func get<T: Decodable & Sendable>(
_ url: URL,
as type: T.Type
) async throws -> T {
let (data, _) = try await session.data(from: url)
return try JSONDecoder().decode(T.self, from: data)
}
}
swift
// Modules/LoginFeature/Package.swift
import PackageDescription
let package = Package(
name: "LoginFeature",
platforms: [.iOS(.v16)],
products: [
.library(name: "LoginFeature", targets: ["LoginFeature"]),
],
dependencies: [
.package(path: "../CoreNetworking"),
.package(path: "../CoreUI"),
],
targets: [
.target(
name: "LoginFeature",
dependencies: ["CoreNetworking", "CoreUI"]
),
.testTarget(name: "LoginFeatureTests", dependencies: ["LoginFeature"]),
]
)
swift
// MyApp.xcodeproj — depend ke ketiga feature package via "Add Local"
// Di app shell:
import LoginFeature
import HomeFeature
import ProfileFeature
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
AppCoordinator()
}
}
}
Keputusan desain:
- Core module tidak tahu feature → tidak ada cyclic dep.
- Feature → Core, satu arah.
- App shell yang compose semua feature.
- Setiap module bisa di-test isolated.
Use Case 2: Library Open Source dengan Multi-Product
Library design system yang punya core + ekstensi opsional.
swift
// swift-tools-version:5.10
import PackageDescription
let package = Package(
name: "MyDesignSystem",
platforms: [.iOS(.v16), .macOS(.v13)],
products: [
// Core: minimum required
.library(name: "DesignTokens", targets: ["DesignTokens"]),
// Optional SwiftUI components
.library(name: "DesignSystemSwiftUI", targets: ["DesignSystemSwiftUI"]),
// Optional UIKit bridges
.library(name: "DesignSystemUIKit", targets: ["DesignSystemUIKit"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.0"),
],
targets: [
.target(
name: "DesignTokens",
resources: [.process("Resources")]
),
.target(
name: "DesignSystemSwiftUI",
dependencies: ["DesignTokens"]
),
.target(
name: "DesignSystemUIKit",
dependencies: ["DesignTokens"]
),
.testTarget(name: "DesignTokensTests", dependencies: ["DesignTokens"]),
.testTarget(name: "DesignSystemSwiftUITests", dependencies: ["DesignSystemSwiftUI"]),
]
)
Keputusan desain:
- Consumer SwiftUI tidak perlu compile UIKit code, dan sebaliknya.
DesignTokens(warna, font, spacing) bisa di-share untuk app extension dengan budget kecil.- Resource (font, image) hanya di-include di module yang butuh.
Use Case 3: Codegen Plugin untuk API Client
Plugin yang generate API client dari OpenAPI spec saat build.
swift
// swift-tools-version:5.10
let package = Package(
name: "MyAPI",
products: [
.library(name: "MyAPI", targets: ["MyAPI"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-openapi-generator.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-openapi-runtime.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-openapi-urlsession.git", from: "1.0.0"),
],
targets: [
.target(
name: "MyAPI",
dependencies: [
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
],
plugins: [
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")
]
),
]
)
swift
# Sources/MyAPI/openapi-generator-config.yaml
generate:
- types
- client
accessModifier: public
swift
# Sources/MyAPI/openapi.yaml (OpenAPI 3.x spec)
openapi: "3.1.0"
info:
title: My API
version: 1.0.0
paths:
/users:
get:
operationId: listUsers
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id: { type: string }
name: { type: string }
swift
// Sources/MyAPI/APIClient.swift — kode user-written
import OpenAPIRuntime
import OpenAPIURLSession
import Foundation
public actor APIClient {
private let client: Client
public init(serverURL: URL) throws {
self.client = Client(
serverURL: serverURL,
transport: URLSessionTransport()
)
}
public func listUsers() async throws -> [Components.Schemas.User] {
let response = try await client.listUsers()
switch response {
case .ok(let ok):
return try ok.body.json
case .undocumented(let status, _):
throw APIError.unexpectedStatus(status)
}
}
}
public enum APIError: Error {
case unexpectedStatus(Int)
}
Keputusan desain:
- Spec OpenAPI = source of truth. Client code auto-regenerate setiap spec berubah.
- Build plugin dijalankan otomatis — tidak ada manual codegen step.
- Type-safe: response
Userter-decode otomatis sesuai schema.
Use Case 4: XCFramework Distribution untuk SDK Closed-Source
SDK pihak ketiga yang di-distribute sebagai binary.
swift
// swift-tools-version:5.10
import PackageDescription
let package = Package(
name: "AnalyticsSDK",
platforms: [.iOS(.v15)],
products: [
.library(name: "AnalyticsSDK", targets: ["AnalyticsSDKWrapper"]),
],
targets: [
.binaryTarget(
name: "AnalyticsCore",
url: "https://cdn.example.com/sdk/v2.3.1/AnalyticsCore.xcframework.zip",
checksum: "f3d4a8b2c1e9f7a6b5d4c3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2"
),
.target(
name: "AnalyticsSDKWrapper",
dependencies: ["AnalyticsCore"],
path: "Sources/Wrapper"
),
]
)
swift
// Sources/Wrapper/AnalyticsSDK.swift — Swift wrapper di sekitar binary
@_exported import AnalyticsCore
public extension AnalyticsCore.Tracker {
/// Swift-idiomatic wrapper around Obj-C API
static func track(event name: String, properties: [String: Any] = [:]) {
AnalyticsCore.Tracker.shared.trackEvent(name, properties: properties)
}
}
Keputusan desain:
- Binary di CDN dengan checksum → integrity verified.
- Wrapper target memungkinkan API improvement tanpa rebuild binary.
@_exported importmembuat consumer cukupimport AnalyticsSDK, tidak perluimport AnalyticsCoreterpisah.