# Swift Package Manager 2026: การสร้าง การเผยแพร่ และคำถามสัมภาษณ์งาน > เชี่ยวชาญ Swift Package Manager ด้วยบทเรียนที่ครอบคลุมนี้ เรียนรู้การสร้าง package จัดการ dependency เผยแพร่ library และเตรียมตัวสำหรับการสัมภาษณ์ iOS - Published: 2026-09-20 - Updated: 2026-09-20 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Swift Package Manager (SPM) จัดการ dependency และการแจกจ่าย package สำหรับโปรเจกต์ Swift ต่างจาก CocoaPods หรือ Carthage ตรงที่ SPM รวมเข้ากับ Xcode และ Swift toolchain โดยตรง ไม่ต้องติดตั้งเครื่องมือภายนอก Swift 6.2 และ 6.3 ได้นำเสนอการตั้งค่าความปลอดภัยหน่วยความจำแบบเข้มงวด การแยก actor เริ่มต้น และระบบ Swift Build ใหม่ ทำให้ SPM เป็นตัวเลือกหลักสำหรับการพัฒนา iOS สมัยใหม่ > **SPM ทำอะไร** > > Swift Package Manager แก้ไข dependency ดาวน์โหลดซอร์สโค้ด คอมไพล์โมดูล และลิงก์เข้ากับ binary สุดท้าย ไฟล์ manifest `Package.swift` เพียงไฟล์เดียวกำหนดทุกอย่าง: dependency, target, product และการตั้งค่า build ## โครงสร้างและไวยากรณ์ของ Manifest Package.swift ทุก Swift package เริ่มต้นด้วยไฟล์ `Package.swift` ที่ root ของ repository manifest นี้ใช้โค้ด Swift เพื่อประกาศโครงสร้าง package, dependency และการกำหนดค่า build ```swift // Package.swift import PackageDescription let package = Package( name: "NetworkKit", platforms: [ .iOS(.v15), .macOS(.v12) ], products: [ .library( name: "NetworkKit", targets: ["NetworkKit"] ) ], dependencies: [ .package( url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0" ) ], targets: [ .target( name: "NetworkKit", dependencies: ["Alamofire"] ), .testTarget( name: "NetworkKitTests", dependencies: ["NetworkKit"] ) ] ) ``` array `platforms` ระบุเป้าหมายการ deploy ขั้นต่ำ ส่วน `products` กำหนดสิ่งที่ package อื่นสามารถ import ได้ ส่วน `targets` แสดงรายการหน่วยคอมไพล์พร้อม dependency ที่เกี่ยวข้อง ## การสร้าง Swift Package จาก Command Line คำสั่ง `swift package init` สร้างโครงร่าง package ใหม่พร้อมโครงสร้างไดเรกทอรีมาตรฐาน flag `--type` กำหนดว่า package จะสร้าง library หรือ executable ```bash # สร้าง library package mkdir NetworkKit && cd NetworkKit swift package init --type=library # โครงสร้างที่สร้างขึ้น: # NetworkKit/ # ├── Package.swift # ├── Sources/ # │ └── NetworkKit/ # │ └── NetworkKit.swift # └── Tests/ # └── NetworkKitTests/ # └── NetworkKitTests.swift ``` รัน `swift build` เพื่อคอมไพล์ package รัน `swift test` เพื่อรัน test suite ทั้งสองคำสั่งใช้การกำหนดค่าจาก `Package.swift` โดยไม่ต้องตั้งค่าเพิ่มเติม ## ข้อกำหนดเวอร์ชัน Dependency และการแก้ไข SPM รองรับกลยุทธ์การระบุเวอร์ชันสามแบบ: เวอร์ชันที่แน่นอน ช่วงเวอร์ชัน และการอ้างอิง branch หรือ commit การเลือกนี้ส่งผลต่อความสามารถในการทำซ้ำและความยืดหยุ่น ```swift // Package.swift dependencies: [ // Semantic versioning: 5.9.0 ถึง major ถัดไป .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0"), // เวอร์ชันที่แน่นอน: ล็อกที่ 5.9.1 .package(url: "https://github.com/Alamofire/Alamofire.git", exact: "5.9.1"), // ช่วงเวอร์ชัน: 5.8.0 ถึง 5.9.9 .package(url: "https://github.com/Alamofire/Alamofire.git", "5.8.0".."5.9.9"), // การอ้างอิง branch: สำหรับการพัฒนา .package(url: "https://github.com/Alamofire/Alamofire.git", branch: "main"), // การอ้างอิง commit: ปักหมุดที่ commit เฉพาะ .package(url: "https://github.com/Alamofire/Alamofire.git", revision: "abc123") ] ``` ไฟล์ `Package.resolved` บันทึกเวอร์ชันที่แน่นอนที่แก้ไขได้ในระหว่างการแก้ไข dependency ไฟล์นี้ควร commit ไปยัง version control เพื่อให้ build สามารถทำซ้ำได้ในทุกสมาชิกทีมและระบบ CI > **Branch Dependency ในโปรดักชัน** > > การอ้างอิง branch และ commit ข้าม semantic versioning การใช้ `branch: "main"` ในแอปโปรดักชันหมายความว่า push ใด ๆ ไปยัง main สามารถทำให้ build เสียได้ สงวนการอ้างอิง branch ไว้สำหรับการพัฒนาที่กำลังดำเนินการกับฟีเจอร์ที่ยังไม่ปล่อย ## การเพิ่ม Package ในโปรเจกต์ Xcode Xcode รวม SPM ผ่านเมนู File นำทางไปที่ File จากนั้น Add Package Dependencies ใส่ URL repository เลือกกฎเวอร์ชัน และเลือก target ที่จะลิงก์ dependency ```swift // AppDelegate.swift import UIKit import Alamofire // พร้อมใช้งานหลังจากเพิ่มผ่าน Xcode @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { AF.request("https://api.example.com/health").response { response in print(response.result) } return true } } ``` Xcode เก็บการอ้างอิง package ในไฟล์ `.xcodeproj` และเวอร์ชันที่แก้ไขแล้วใน `Package.resolved` ที่ root โปรเจกต์ โฟลเดอร์ Derived Data แคช package ที่ดาวน์โหลด ## การพัฒนา Package ในเครื่องด้วย Path Dependency ในระหว่างการพัฒนา การชี้ไปที่ path ในเครื่องแทน URL ระยะไกลช่วยให้สามารถทำซ้ำได้อย่างรวดเร็วโดยไม่ต้องเผยแพร่เวอร์ชันกลาง เทคนิคนี้เหมาะกับการตั้งค่า monorepo และการพัฒนาฟีเจอร์ ```swift // Package.swift ใน consuming package dependencies: [ // Path ในเครื่องสำหรับการพัฒนา .package(path: "../NetworkKit"), // URL ระยะไกลสำหรับ release // .package(url: "https://github.com/company/NetworkKit.git", from: "1.0.0") ] ``` สลับระหว่าง dependency ในเครื่องและระยะไกลโดย comment บรรทัดที่ไม่ใช้งาน Xcode และ Swift CLI แก้ไข path dependency เทียบกับ consuming package ## การเผยแพร่ Swift Package ไปยัง GitHub การเผยแพร่ต้องมี Git repository พร้อม tag เวอร์ชันความหมาย SPM ถือว่า Git tag เป็นเวอร์ชัน release [Swift Package Index](https://swiftpackageindex.com) จัดทำดัชนี package สาธารณะโดยอัตโนมัติ ```bash # เริ่มต้น repository และ push git init git add . git commit -m "Initial commit" git remote add origin https://github.com/username/NetworkKit.git git push -u origin main # สร้าง tag เวอร์ชัน git tag 1.0.0 git push origin 1.0.0 # Package อื่นสามารถขึ้นอยู่กับ: # .package(url: "https://github.com/username/NetworkKit.git", from: "1.0.0") ``` ปฏิบัติตามข้อตกลง [semantic versioning](https://semver.org): เพิ่ม major สำหรับ breaking changes, minor สำหรับฟีเจอร์ใหม่ และ patch สำหรับแก้ไขบั๊ก SPM สันนิษฐานว่าปฏิบัติตามกฎเหล่านี้เมื่อแก้ไขข้อกำหนดเวอร์ชัน `from:` ## การตั้งค่า Package Swift 6.2 และ 6.3 Swift 6.2 แนะนำการกำหนดค่าโหมดภาษาต่อ target และการตั้งค่าความปลอดภัยหน่วยความจำแบบเข้มงวด Swift 6.3 เพิ่มการรวม Swift Build เป็นระบบ build แบบ opt-in ```swift // Package.swift พร้อมฟีเจอร์ Swift 6.2+ import PackageDescription let package = Package( name: "SafeNetworkKit", platforms: [.iOS(.v17)], products: [ .library(name: "SafeNetworkKit", targets: ["SafeNetworkKit"]) ], targets: [ .target( name: "SafeNetworkKit", swiftSettings: [ // เปิดใช้โหมดภาษา Swift 6 สำหรับ target นี้เท่านั้น .swiftLanguageMode(.v6), // เปิดใช้การตรวจสอบความปลอดภัยหน่วยความจำแบบเข้มงวด (SE-0458) .enableExperimentalFeature("StrictMemorySafety"), // ตั้งค่าการแยก actor เริ่มต้น (SE-0466) .enableExperimentalFeature("GlobalActorIsolation") ] ) ] ) ``` การตั้งค่า `swiftLanguageMode` อนุญาตให้นำฟีเจอร์ Swift 6 มาใช้ทีละน้อยในทั้ง codebase Target ต่าง ๆ สามารถใช้โหมดภาษาที่แตกต่างกันภายใน package เดียวกัน ## การสร้าง SBOM สำหรับการปฏิบัติตามความปลอดภัย SE-0509 เพิ่มการสร้าง Software Bill of Materials แบบ native ใน Swift 6.3 เอกสาร SBOM แสดงรายการ dependency ทั้งหมดและเวอร์ชันสำหรับการตรวจสอบความปลอดภัยและการปฏิบัติตามกฎระเบียบ ```bash # สร้าง SBOM ในรูปแบบ CycloneDX swift build --sbom-spec cyclonedx # สร้าง SBOM โดยใช้ subcommand เฉพาะ swift package generate-sbom --format spdx # ผลลัพธ์รวม: # - ชื่อและเวอร์ชัน package # - dependency แบบ transitive ทั้งหมด # - ข้อมูลลิขสิทธิ์ # - URL repository ต้นทาง ``` สภาพแวดล้อมองค์กรและสัญญาภาครัฐต้องการเอกสาร SBOM มากขึ้น รูปแบบ CycloneDX และ SPDX รวมกับเครื่องมือสแกนช่องโหว่มาตรฐาน ## Binary Target และการแจกจ่าย XCFramework Binary target อนุญาตให้แจกจ่าย framework ที่คอมไพล์แล้วแทนซอร์สโค้ด XCFramework รวม binary สำหรับหลายแพลตฟอร์มและสถาปัตยกรรม ```swift // Package.swift พร้อม binary target import PackageDescription let package = Package( name: "AnalyticsSDK", platforms: [.iOS(.v14)], products: [ .library(name: "AnalyticsSDK", targets: ["AnalyticsSDK"]) ], targets: [ .binaryTarget( name: "AnalyticsSDK", url: "https://releases.example.com/AnalyticsSDK-2.0.0.xcframework.zip", checksum: "abc123def456..." ) ] ) // สร้าง checksum: // swift package compute-checksum AnalyticsSDK-2.0.0.xcframework.zip ``` Binary target ลดเวลา build สำหรับผู้ใช้และปกป้องการใช้งานที่เป็นกรรมสิทธิ์ Checksum รับรองความสมบูรณ์ของการดาวน์โหลด ## คำถามสัมภาษณ์ทั่วไปเกี่ยวกับ Swift Package Manager การสัมภาษณ์ทางเทคนิคสำหรับตำแหน่ง iOS มักรวมคำถามเกี่ยวกับ SPM คำถามเหล่านี้มีตั้งแต่การใช้งานพื้นฐานไปจนถึงการตัดสินใจด้านสถาปัตยกรรม **Q: SPM แตกต่างจาก CocoaPods และ Carthage อย่างไร?** SPM รวมเข้ากับ Xcode และ Swift toolchain โดยไม่ต้องใช้เครื่องมือภายนอก CocoaPods ใช้ repository spec ส่วนกลางและแก้ไขโครงสร้าง workspace ของ Xcode Carthage build framework ในขั้นตอนแยกต่างหากโดยไม่มีการรวม Xcode SPM แก้ไข dependency และ build ในกระบวนการรวมเดียว [เอกสาร Apple เกี่ยวกับ Swift packages](https://developer.apple.com/documentation/xcode/swift-packages) ครอบคลุมเครื่องมืออย่างเป็นทางการ **Q: เกิดอะไรขึ้นในระหว่างการแก้ไข dependency?** SPM อ่าน manifest `Package.swift` แบบ recursive สร้างกราฟ dependency จากนั้นใช้ข้อจำกัดเวอร์ชันเพื่อหาเวอร์ชันที่เข้ากันได้สำหรับทุก package Resolver เขียนเวอร์ชันที่แน่นอนไปยัง `Package.resolved` ความขัดแย้งเกิดขึ้นเมื่อ package สองตัวต้องการเวอร์ชันที่เข้ากันไม่ได้ของ dependency ที่ใช้ร่วมกัน **Q: จัดการกับความขัดแย้ง diamond dependency อย่างไร?** เมื่อ package A และ B ทั้งคู่ขึ้นอยู่กับ package C ที่มีข้อกำหนดเวอร์ชันที่เข้ากันไม่ได้ การแก้ไข SPM ล้มเหลว วิธีแก้ปัญหารวมถึง: อัปเดต consumer หนึ่งตัวให้รองรับช่วงเวอร์ชันที่กว้างขึ้น fork package ที่จำกัด หรือใช้ module aliasing หากความขัดแย้งระหว่าง package ต่างกันที่มีชื่อโมดูลเหมือนกัน ```swift // Module aliasing สำหรับความขัดแย้งของชื่อ .target( name: "MyApp", dependencies: [ .product(name: "Logging", package: "swift-log", moduleAliases: ["Logging": "SwiftLogging"]) ] ) ``` **Q: เมื่อใดควรใช้ binary target แทนการแจกจ่ายซอร์ส?** Binary target เหมาะกับ SDK ที่เป็นกรรมสิทธิ์ที่การเปิดเผยซอร์สไม่เป็นที่ยอมรับ dependency ขนาดใหญ่ที่เวลาคอมไพล์ส่งผลต่อประสิทธิภาพของนักพัฒนา และ library จากผู้ขายที่คอมไพล์ล่วงหน้า การแจกจ่ายซอร์สยังคงเป็นที่นิยมสำหรับโปรเจกต์ open source และ library ภายในที่การ debug เข้าไปใน dependency เพิ่มคุณค่า ## การย้ายจาก CocoaPods ไปยัง Swift Package Manager การย้ายต้องแทนที่รายการ Podfile ด้วยการอ้างอิง SPM package ไม่ใช่ทุก CocoaPods จะมี SPM เทียบเท่า ดังนั้นควรตรวจสอบความพร้อมใช้งานที่ [Swift Package Index](https://swiftpackageindex.com) ก่อนเริ่ม ```ruby # ก่อน: Podfile pod 'Alamofire', '~> 5.9' pod 'SwiftyJSON', '~> 5.0' pod 'Kingfisher', '~> 7.0' ``` ```swift // หลัง: Package dependency ใน Xcode // File > Add Package Dependencies สำหรับแต่ละตัว: // https://github.com/Alamofire/Alamofire.git from 5.9.0 // https://github.com/SwiftyJSON/SwiftyJSON.git from 5.0.0 // https://github.com/onevcat/Kingfisher.git from 7.0.0 ``` ลบ Podfile, Podfile.lock และไดเรกทอรี Pods หลังการย้าย รัน `pod deintegrate` เพื่อลบการแก้ไข workspace ของ CocoaPods คำสั่ง import ในไฟล์ Swift ยังคงไม่เปลี่ยนแปลง ## แนวปฏิบัติที่ดีที่สุดของ SPM สำหรับแอปโปรดักชัน - ปักหมุดเวอร์ชัน major ด้วย `from:` เพื่อความเสถียรในขณะที่รับอัปเดต minor และ patch - Commit `Package.resolved` เพื่อรับรองว่า build สามารถทำซ้ำได้ในทีม - ใช้ package ในเครื่องในระหว่างการพัฒนาที่กำลังดำเนินการ เปลี่ยนเป็น URL ระยะไกลก่อน merge - แยก dependency เฉพาะ test โดยใช้ `testTarget` เพื่อหลีกเลี่ยงการรวมใน release build - บันทึกเวอร์ชัน Swift tools ขั้นต่ำที่ด้านบนของ manifest: `// swift-tools-version: 5.10` - ตรวจสอบ build ของ package บน CI ก่อนสร้าง tag release > **Swift Tools Version** > > comment `// swift-tools-version:` ต้องปรากฏที่บรรทัดแรกของ Package.swift ซึ่งกำหนดว่าเวอร์ชัน API ของ PackageDescription ใดที่ manifest ใช้ Swift 6.0 เพิ่มความยืดหยุ่นในการอนุญาตให้ comment นี้อยู่ในบรรทัดถัดไปสำหรับ header ลิขสิทธิ์ ## ประเด็นสำคัญสำหรับนักพัฒนา iOS ที่ใช้ SPM - SPM รวมเข้ากับ Xcode แบบ native ขจัดค่าใช้จ่ายในการตั้งค่า CocoaPods และ Carthage - manifest `Package.swift` ใช้โค้ด Swift ช่วยให้การประกาศ dependency ถูกตรวจสอบประเภท - ข้อกำหนดเวอร์ชันรองรับช่วง semantic versioning เวอร์ชันที่แน่นอน และการอ้างอิง branch - `Package.resolved` ล็อกเวอร์ชัน dependency สำหรับ build ที่ทำซ้ำได้ - Swift 6.2 เพิ่มโหมดภาษาต่อ target และการตั้งค่าความปลอดภัยหน่วยความจำแบบเข้มงวด - Swift 6.3 แนะนำการสร้าง SBOM สำหรับเอกสารการปฏิบัติตาม - Binary target แจกจ่าย XCFramework ที่คอมไพล์ล่วงหน้าเมื่อการแจกจ่ายซอร์สไม่เหมาะสม - คำถามสัมภาษณ์มุ่งเน้นที่ความขัดแย้งในการแก้ไข กลยุทธ์การย้าย และการแลกเปลี่ยนด้านสถาปัตยกรรมระหว่าง SPM และทางเลือกอื่น สำหรับการเตรียมสัมภาษณ์ iOS อย่างครอบคลุม ให้ทบทวนโมดูล [การจัดการ state SwiftUI](/technologies/ios/interview-questions/swiftui-state-management) และ [การเขียนโปรแกรมเชิง protocol](/technologies/ios/interview-questions/protocol-oriented-programming) บน SharpSkill --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/ios/swift-package-manager-tutorial-2026