Ok got it working now ! 🎉
I was missing copying the contents to my own file, so we're still able to access it once the original is gone.
public func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: any UICollectionViewDropCoordinator) {
for item in coordinator.items {
// Check if the dropped item is a URL (for videos)
if item.dragItem.itemProvider.hasItemConformingToTypeIdentifier(AVFileType.mov.rawValue) {
item.dragItem.itemProvider.loadFileRepresentation(forTypeIdentifier: AVFileType.mov.rawValue) { (videoURL, error) in
if let droppedVideoURL = videoURL as? URL {
let fileManager = FileManager.default
let destination = fileManager.temporaryDirectory.appendingPathComponent("video123.mov")
try? fileManager.copyItem(at: droppedVideoURL, to: destination)
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: destination)
}) { saved, error in
if saved {
print("SAVED!")
}
}
}
}
}
}
Post
Replies
Boosts
Views
Activity
I use the UICollectionViewDropDelegate to get the dropped video URL:
public func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: any UICollectionViewDropCoordinator) {
let videoSaver = VideoSaver()
for item in coordinator.items {
// Check if the dropped item is a URL (for videos)
if item.dragItem.itemProvider.hasItemConformingToTypeIdentifier(AVFileType.mov.rawValue) {
item.dragItem.itemProvider.loadFileRepresentation(forTypeIdentifier: AVFileType.mov.rawValue) { (videoURL, error) in
if let droppedVideoURL = videoURL as? URL {
videoSaver.writeToPhotoAlbum(droppedVideoURL)
}
}
}
}
Here's my VideoSaver:
final class VideoSaver: NSObject {
func writeToPhotoAlbum(_ videoPath: URL) {
// `isCompatible` is `true` when I test on my iPhone, but is `false` on the iPad Sim. 🙈
let isCompatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoPath.absoluteString)
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoPath)
}) { saved, error in
// This is the error:
// (Error?) domain: "PHPhotosErrorDomain" - code: 18446744073709551615 {
// _userInfo = 0x0000000000000000
// }
if saved {
print("SAVED!")
}
}
}
On the iPad Simulator I additionally get this error from calling: UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoPath.absoluteString). I do NOT get this error on my real iPhone:
` ``Video file:///Users/manuel/Library/Developer/CoreSimulator/Devices/6A7D334E-A84E-4585-B7E0-CF2F02C76197/data/Containers/Data/Application/F23068E9-0517-4EF3-B82F-4E45D9C05745/tmp/.com.apple.Foundation.NSItemProvider.tZZ8Jd/IMG_0839.mov cannot be saved to the photo library: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSUnderlyingError=0x600000c58210 {Error Domain=NSOSStatusErrorDomain Code=-17913 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-17913), NSLocalizedRecoverySuggestion=XXXXDEFAULTVALUEXXXX, NSURL=file:/Users/manuel/Library/Developer/CoreSimulator/Devices/6A7D334E-A84E-4585-B7E0-CF2F02C76197/data/Containers/Data/Application/F23068E9-0517-4EF3-B82F-4E45D9C05745/tmp/.com.apple.Foundation.NSItemProvider.tZZ8Jd/IMG_0839.mov -- file:///, AVErrorFailedDependenciesKey=(
"assetProperty_CameraRollValidation"
), NSLocalizedDescription=The operation could not be completed}```
This is still happening on Xcode 13.2.1
I found that setting a custom back button will disable the menu:
let backButton = UIBarButtonItem(title: "< back",
style: .done,
target: self,
action: #selector(popVC(sender:)))
vc.navigationItem.leftBarButtonItem = backButton
@objc
func popVC(sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
Found this on UIBarButtonItem header:
/// When non-nil the menu is presented, the gesture used to trigger
/// the menu is based on if the bar button item would normally trigger an action when tapped.
@available(iOS 14.0, *)
@NSCopying open var menu: UIMenu?
But setting the backBarButtonItem.menu property to nil does nothing:
vc.navigationItem.backBarButtonItem?.menu = nil	// still displays the menu