PhotoKit เป็นเฟรมเวิร์กของ Apple สำหรับทำงานกับคลังสื่อบน iOS และ macOS ให้การเข้าถึงรูปภาพ วิดีโอ และ Live Photos บนอุปกรณ์โดยตรง ตาม เอกสารของ Apple เฟรมเวิร์กนี้แทนที่ AssetsLibrary แบบเก่าและรองรับ iCloud อัลบั้ม การแก้ไข และ Change Tracking PhotoKit มอบ API แบบรวมสำหรับการสอบถาม การแคช และการเปลี่ยนแปลงคลังสื่อพร้อมการซิงค์อัตโนมัติผ่าน iCloud
ประเด็นสำคัญ
PhotoKit เป็นเฟรมเวิร์กของ Apple (เปิดตัวใน iOS 8, macOS 10.11) ที่ให้ API เชิงวัตถุสำหรับทำงานกับคลังสื่อของระบบ แตกต่างจาก AssetsLibrary ตรงที่ PhotoKit ถือว่าคลังสื่อเป็นฐานข้อมูล: การสอบถามส่งคืนวัตถุ PHAsset, PHCollection และ PHCollectionList ที่แสดงเนื้อหาและโครงสร้างการจัดเก็บ
PhotoKit รองรับสื่อทุกประเภท: รูปภาพ (JPEG, HEIF, RAW), วิดีโอ (MOV, MP4), Live Photos และภาพถ่ายต่อเนื่อง เฟรมเวิร์กจัดการการซิงค์ iCloud โดยอัตโนมัติ: หากรูปภาพถูกเก็บใน iCloud PhotoKit จะขอผ่านเครือข่ายและรายงานความคืบหน้าผ่าน PHImageRequestOptions.progressHandler
คุณสมบัติหลักของ PhotoKit คือโมเดลข้อมูลที่ใช้ PHObject พร้อมตัวระบุเฉพาะภายในเครื่อง (localIdentifier) ที่คงที่ระหว่างเซสชัน ช่วยให้คุณบันทึกการอ้างอิงถึงวัตถุสื่อและกู้คืนหลังจากเริ่มแอปใหม่โดยไม่ต้องสอบถามอีกครั้ง
PhotoKit สร้างขึ้นบนสามระดับ: โมเดลข้อมูล (PHObject), การสอบถาม (PHFetchResult) และการเปลี่ยนแปลง (PHPhotoLibrary.performChanges) โมเดลข้อมูลเป็นลำดับชั้น: PHAsset (รูปภาพ/วิดีโอ) อยู่ใน PHAssetCollection (อัลบั้ม) และอัลบั้มถูกจัดกลุ่มใน PHCollectionList (โฟลเดอร์)
การสอบถามดำเนินการผ่าน PHAsset.fetchAssets และ PHAssetCollection.fetchAssetCollections วิธีการ fetch ทั้งหมดเป็นแบบซิงโครนัสและส่งคืน PHFetchResult ซึ่งดำเนินการสอบถามกับฐานข้อมูลคลังสื่อทันที PHFetchResult รองรับการเข้าถึงตามดัชนีอย่างรวดเร็ว (object(at:)) และการแจงนับผ่าน enumerateObjects
PHFetchOptions เป็นวัตถุสำหรับกำหนดค่าการสอบถาม: การเรียงลำดับ (sortDescriptors), ภาคแสดง (predicate), การรวมสื่อที่ซ่อนและถูกลบ (includeHiddenAssets, includeAllBurstAssets) ตัวเลือก fetch อนุญาตให้กรองตามชนิดสื่อ: PHAssetMediaType.image, .video, .audio
PhotoKit ประกอบด้วยชุดคลาสสำหรับการเข้าถึง การสอบถาม และการปรับเปลี่ยนคลังสื่อ การทำความเข้าใจแต่ละคลาสเป็นสิ่งจำเป็นสำหรับการทำงานกับเฟรมเวิร์กอย่างมีประสิทธิภาพ
PHAsset เป็นวัตถุที่ไม่สามารถเปลี่ยนแปลงได้ซึ่งแสดงรายการสื่อเดี่ยว ประกอบด้วยเมทาดาทา: mediaType, mediaSubtypes, creationDate, location, pixelWidth, pixelHeight, duration (สำหรับวิดีโอ), isFavorite, burstIdentifier LocalIdentifier เป็นคีย์สตริงที่เสถียรซึ่งสามารถเข้าถึงได้แม้หลังจากเริ่มแอปใหม่
PHAssetCollection เป็นกลุ่มสื่อ: อัลบั้มระบบ (Recents, Favorites, Selfies, Screenshots), อัลบั้มผู้ใช้ หรือ Moments (จัดกลุ่มอัตโนมัติตามเวลาและสถานที่) คุณลักษณะ: localizedTitle, assetCollectionType, assetCollectionSubtype, startDate, endDate
PHCollectionList เป็นโฟลเดอร์ที่ประกอบด้วยอัลบั้ม (PHAssetCollection) หรือโฟลเดอร์อื่น ๆ ใช้น้อย โดยส่วนใหญ่ใช้แสดงลำดับชั้นในอินเทอร์เฟซผู้ใช้
PhotoKit ไม่ส่งคืน UIImage โดยตรงจาก PHAsset — คุณต้องขอรูปภาพผ่าน PHImageManager ซึ่งรับประกันว่ารูปภาพจะถูกโหลดด้วยการรองรับ iCloud การแคช และขนาดที่ต้องการ
| ส่วนประกอบ | วัตถุประสงค์ | คุณสมบัติ |
|---|---|---|
| PHImageManager.default() | ตัวจัดการมาตรฐานสำหรับคำขอเดี่ยว | ไม่มีการแคชระหว่างคำขอ |
| PHCachingImageManager | ตัวจัดการพร้อมโหลดล่วงหน้าสำหรับคอลเลกชัน | startCachingImages เพื่อการเลื่อนที่ราบรื่น |
| PHImageRequestOptions | การตั้งค่าคำขอ: ขนาด โหมด การส่งมอบ | synchronous, deliveryMode, progressHandler |
| PHImageRequestID | ตัวระบุคำขอสำหรับการยกเลิก | cancelImageRequest(PHImageRequestID) |
PHImageManager รองรับสามโหมดการส่งมอบ: opportunistic (เวอร์ชันลดขนาดก่อน จากนั้นเต็มรูปแบบ), highQualityFormat (เฉพาะคุณภาพเต็ม) และ fastFormat (เวอร์ชันที่เร็วที่สุดที่มี) สำหรับคอลเลกชัน ให้ใช้ PHCachingImageManager พร้อมโหลดรูปภาพล่วงหน้าสำหรับเซลล์ที่มองเห็นเสมอ
PhotoKit ใช้สำหรับสร้างแกลเลอรีที่กำหนดเอง โปรแกรมแก้ไข และแอปพลิเคชันสื่อ มาดูสามสถานการณ์หลักกัน
PHAsset.fetchAssets พร้อม PHFetchOptions ที่เรียงตามวันที่สร้างเป็นการสอบถามพื้นฐานสำหรับสร้างแกลเลอรีรูปภาพที่กำหนดเอง PHFetchResult รองรับการโหลดแบบขี้เกียจและการเข้าถึงแบบสตรีม
let options = PHFetchOptions()
options.sortDescriptors = [NSSortDescriptor(
key: "creationDate",
ascending: .false
)]
options.predicate = NSPredicate(
format: "mediaType == %d",
PHAssetMediaType.image.rawValue
)
let allPhotos = PHAsset.fetchAssets(with: options)
print("พบ \(allPhotos.count) รูปภาพ")
allPhotos.enumerateObjects { asset, index, stop in
print("รูปภาพ \(index): \(asset.localIdentifier)")
}
PHFetchResult เป็นคอนเทนเนอร์ที่ ปลอดภัยต่อเธรด การเข้าถึงวัตถุตามดัชนีผ่าน object(at:) ไม่บล็อกอินเทอร์เฟซผู้ใช้ แต่การขอรูปภาพผ่าน PHImageManager ควรดำเนินการแบบอะซิงโครนัส
PHCachingImageManager เป็นคลาสย่อยของ PHImageManager ที่มีเมธอด startCachingImages และ stopCachingImages สำหรับโหลดล่วงหน้า ใช้ใน UICollectionView เพื่อการเลื่อนที่ราบรื่น
let cachingManager = PHCachingImageManager()
let targetSize = CGSize(width: 200, height: 200)
// โหลดล่วงหน้าสำหรับเซลล์ที่มองเห็น
cachingManager.startCachingImages(
for: visibleAssets,
targetSize: targetSize,
contentMode: .aspectFill,
options: nil
)
// ขอรูปภาพผ่าน PHImageRequestOptions พร้อมการสำรอง iCloud
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .opportunistic
requestOptions.isNetworkAccessAllowed = .true
requestOptions.progressHandler = { progress, error, stop, info in
DispatchQueue.main.async {
print("กำลังดาวน์โหลดจาก iCloud: \(progress * 100)%")
}
}
let requestID = cachingManager.requestImage(
for: asset,
targetSize: targetSize,
contentMode: .aspectFill,
options: requestOptions
) { image, info in
print("ได้รับรูปภาพ: \(image?.size ?? .zero)")
}
การเปลี่ยนแปลงในคลังสื่อดำเนินการผ่าน PHPhotoLibrary.shared().performChanges ภายในบล็อก changeRequest การดำเนินการทั้งหมดถูกจัดเป็นชุดและนำไปใช้แบบธุรกรรม
PHPhotoLibrary.shared().performChanges {
let changeRequest = PHAssetChangeRequest(for: asset)
changeRequest.isFavorite = .true
} completionHandler: { success, error in
if success {
print("เพิ่มในรายการโปรดแล้ว")
}
}
PhotoKit มีกลไกสำหรับสังเกตการเปลี่ยนแปลงในคลังสื่อผ่านโพรโทคอล PHPhotoLibraryChangeObserver เมื่อมีการเปลี่ยนแปลงใด ๆ (การสร้าง การลบ การแก้ไข) เมธอด photoLibraryDidChange จะถูกเรียกพร้อมวัตถุ PHChange
PHChange ประกอบด้วย changeDetails สำหรับการสอบถามแต่ละชนิด: PHFetchResultChangeDetails พร้อม removedIndexes, insertedIndexes, changedIndexes ซึ่งช่วยให้สามารถนำการเปลี่ยนแปลงไปใช้อินเทอร์เฟซผู้ใช้ด้วยอนิเมชัน: performBatchUpdates พร้อม move, insert, delete สำหรับ UICollectionView
class PhotosViewController: UIViewController {
var fetchResult: PHFetchResult>PHAsset>?
override func viewDidLoad() {
super.viewDidLoad()
PHPhotoLibrary.shared().register(self)
}
deinit {
PHPhotoLibrary.shared().unregisterChangeObserver(self)
}
}
extension PhotosViewController: PHPhotoLibraryChangeObserver {
func photoLibraryDidChange(_ changeInstance: PHChange) {
guard let fetchResult,
let details = changeInstance.changeDetails(for: fetchResult)
else { return }
DispatchQueue.main.async {
self.fetchResult = details.fetchResultAfterChanges
// ใช้การเปลี่ยนแปลงกับ collectionView
}
}
}
PhotoKit รองรับการแก้ไขสื่อผ่านกลไก PHContentEditingInput และ PHContentEditingOutput แอปขอ editingInput พร้อมข้อมูลต้นฉบับ ใช้การเปลี่ยนแปลง และบันทึกผลลัพธ์ผ่าน editingOutput เฟรมเวิร์กเก็บต้นฉบับไว้โดยอัตโนมัติ ทำให้ผู้ใช้สามารถย้อนกลับการเปลี่ยนแปลงโดยรีเซ็ตเป็นต้นฉบับ
รูปภาพ RAW (DNG, CR2, NEF) รองรับผ่าน PHAssetResourceManager ซึ่งให้การเข้าถึงไฟล์ RAW ต้นฉบับ สำหรับการประมวลผล RAW แนะนำให้ใช้ CoreImage พร้อมตัวกรอง CIRAWFilter ซึ่งรองรับการปรับอุณหภูมิ การเปิดรับแสง และความคมชัด PhotoKit ยังรองรับส่วนขยายโปรแกรมแก้ไขผ่าน Photo Editing Extension (iOS) — แอปสามารถถูกเรียกจากโปรแกรมแก้ไขระบบเพื่อประมวลผลรูปภาพหรือวิดีโอที่เลือก
PhotoKit เป็นเฟรมเวิร์กที่ทรงพลังแต่ใช้ทรัพยากรมาก การใช้งานที่ไม่ถูกต้องอาจทำให้เกิดการกระตุกเมื่อเลื่อนและการใช้หน่วยความจำมากเกินไป ปฏิบัติตามคำแนะนำเหล่านี้เพื่อประสิทธิภาพที่ดีที่สุด
PHLivePhoto ต้องใช้คำขอแยกต่างหากผ่าน PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:) อย่าขอ Live Photo สำหรับเซลล์ที่แสดงเฉพาะรูปภาพ — ใช้ PHLivePhotoBadge เป็นตัวบ่งชี้
คำถามที่พบบ่อย
PhotoKit เป็นเฟรมเวิร์กที่ทันสมัยของ Apple สำหรับทำงานกับคลังสื่อ เปิดตัวใน iOS 8 แตกต่างจาก AssetsLibrary แบบเก่า PhotoKit มอบโมเดลวัตถุ PHAsset, PHFetchResult พร้อมการค้นหาที่รวดเร็ว, การรองรับ iCloud และ Change Tracking สำหรับสังเกตการเปลี่ยนแปลง
เรียก PHPhotoLibrary.requestAuthorization(for: .readWrite) พร้อมตัวจัดการ callback หลังจากได้รับสถานะ .authorized คุณสามารถดำเนินการสอบถาม PHAsset.fetchAssets การเข้าถึงแบบเขียนต้องได้รับสิทธิ์ .readWrite สำหรับอ่านอย่างเดียว — .addOnly
ใช้ PHImageManager.default().requestImage พร้อมพารามิเตอร์: asset, targetSize, contentMode และ PHImageRequestOptions เมธอดแบบอะซิงโครนัสส่งคืน PHImageRequestID ซึ่งช่วยให้คุณยกเลิกคำขอได้ สำหรับคอลเลกชัน ให้ใช้ PHCachingImageManager พร้อมโหลดล่วงหน้า
ลงทะเบียนผู้สังเกตผ่าน PHPhotoLibrary.shared().register(self) และใช้โพรโทคอล PHPhotoLibraryChangeObserver ในเมธอด photoLibraryDidChange รับ PHChange พร้อม changeDetails สำหรับแต่ละ fetchResult และนำการเปลี่ยนแปลงไปใช้อินเทอร์เฟซผู้ใช้ด้วยอนิเมชัน
ใน PHImageRequestOptions ตั้งค่า isNetworkAccessAllowed = true และ progressHandler สำหรับติดตามความคืบหน้าการดาวน์โหลด iCloud ระหว่างการเลื่อนอย่างรวดเร็ว ให้ปิดการเข้าถึงเครือข่ายและโหลดเฉพาะเวอร์ชันภายในเครื่องเพื่อหลีกเลี่ยงความหน่วงในการเลื่อน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ