How to delete the last photo in Swift iOS8? - ios

I try to get the last photo from camera roll and delete it.Now I get the last photo but have problems in deleting the last photo.
I tried this way but I delete all photos,so I plan to build a new PHFetchResult which only include the last photo but I don't know how to do that.
PHPhotoLibrary.sharedPhotoLibrary().performChanges( {
PHAssetChangeRequest.deleteAssets(fetchResult)},
completionHandler: {
success, error in
NSLog("Finished deleting asset. %#", (success ? "Success" : error))
})
Thank all of you to answer my question!

I guess the problem lies in your fetchResult.
You will have to pass an array that contains only latest image from photo library.
Try making that array as follows-
var fetchOptions: PHFetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
var fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)
if (fetchResult.lastObject != nil) {
var lastAsset: PHAsset = fetchResult.lastObject as PHAsset
let arrayToDelete = NSArray(object: lastAsset)
PHPhotoLibrary.sharedPhotoLibrary().performChanges( {
PHAssetChangeRequest.deleteAssets(arrayToDelete)},
completionHandler: {
success, error in
NSLog("Finished deleting asset. %#", (success ? "Success" : error))
})
}
See this link.

Related

Get Video or Video Info Without open Gallery Swift

I am trying to get Video without open Gallery or UIImagePickerControllerlike I got success in getting images without open gallery. Is there any way to get files without open UIImagePickerController.
Can someone please explain to me how to get files without open UIImagePickerController. Any help would be greatly appreciated.
Thanks in advance.
For example, using the following code, you can get the latest user video:
import Photos
let options = PHFetchOptions()
options.fetchLimit = 1
let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
options.sortDescriptors = [sortDescriptor]
let fetchResult = PHAsset.fetchAssets(with: .video, options: options)
if fetchResult.count == 0 {
// user has no video...
return
}
let asset = fetchResult[0]
let requestOptions = PHVideoRequestOptions()
let manager = PHImageManager.default()
Then, if you want to get the video itself, use the following code:
manager.requestAVAsset(forVideo: asset, options: requestOptions, resultHandler: { oAsset, oAudioMix, oDict in
if let urlAsset = oAsset as? AVURLAsset {
let url = urlAsset.url
// use URL to get file content
}
})
Otherwise, if you just want to play the video, use the following code:
manager.requestPlayerItem(forVideo: asset, options: requestOptions, resultHandler: { oPlayerItem, oDict in
// do something with oPlayerItem
})
For more information you can read this

Save video to the gallery and get the path for the video stored to Gallery

I want to save a video chosen from UIImagePickerController to the Photos album.
After that i need to fetch the URL to the saved path. I saw some pre-existing questions which answer with use of ALAssetsLibrary which is now deprecated.
Like : Save video on the gallery and store the path to the video
Can someone please guide me to use Photo's framework and achieve the above desired result. Kindly correct me if I am wrong anywhere.
Thanks!!
This worked for me perfectly.
Swift 3.1 ->
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url!)
}) { saved, error in
if saved {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
// After uploading we fetch the PHAsset for most recent video and then get its current location url
let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions).lastObject
PHImageManager().requestAVAsset(forVideo: fetchResult!, options: nil, resultHandler: { (avurlAsset, audioMix, dict) in
let newObj = avurlAsset as! AVURLAsset
print(newObj.url)
// This is the URL we need now to access the video from gallery directly.
})
}
}
First, you need to set the following permission in your app's plist file:
Privacy - Photo Library Usage Description
Provide a string that is presented to the user explaining why you are requesting the permission.
Next,
import photos
Then use this code to store video
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: fileURL)
}) { saved, error in
if saved {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions).firstObject
// fetchResult is your latest video PHAsset
// To fetch latest image replace .video with .image
}
}
To get url from PHAsset, refer to this question's answer
If you want to fetch the saved element (not using a sort descriptor with date order), you can do it this way:
var changeRequest: PHAssetChangeRequest?
var blockPlaceholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
changeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url!)
blockPlaceholder = changeRequest?.placeholderForCreatedAsset
}) { saved, error in
if saved {
guard let placeholder = blockPlaceholder else {
return
}
let fetchOptions = PHFetchOptions()
let fetchResult:PHFetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [placeholder.localIdentifier], options: fetchOptions)
if let asset = fetchResult.firstObject {
//here you have the PHAsset
}
}
}
Try like this!
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
if mediaType.isEqualToString(kUTTypeMovie as NSString as String) || mediaType.isEqualToString(kUTTypeVideo as NSString as String){
let videoPath = info[UIImagePickerControllerMediaURL] as! NSURL // Path of video Url
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(videoPath)
let assetPlaceholder = createAssetRequest?.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
albumChangeRequest!.addAssets([assetPlaceholder!])
}, completionHandler: { (success, error) in
NSLog("Adding video to Library ->%#", (success ? "Success" : "Error"))
picker.dismissViewControllerAnimated(true, completion: nil)
})
}
}
Here's the answer for Objective-C
Code Sample:
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:[NSURL URLWithString:urlOfFile]];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc]init];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:false]];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:fetchOptions];
PHAsset *lastAsset = [fetchResult lastObject];
[[PHImageManager defaultManager] requestAVAssetForVideo:lastAsset options:nil resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
//here's the url to the file
NSURL *url = (NSURL *)[(AVURLAsset *)asset URL];
}else{
NSLog(#"%#",error.description);
}
}];
I do this by creating extension of the URL Class
extension URL {
func saveVideo( success:#escaping (Bool,URL?)->()){
URLSession.shared.downloadTask(with: URLRequest(url: self)) { (url, response, error) in
let mgr = FileManager.default
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let destination = URL(fileURLWithPath: String(format: "%#/%#", documentsPath, "video.mp4"))
try? mgr.moveItem(atPath: /url?.path, toPath: /destination.path)
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: destination)
}) { completed, error in
if completed {
print("Video is saved!")
success(true,destination)
}
if error != nil{
success(false,nil)
}
}
}.resume()
}
}
when you want to save and play you can use this in ViewController as
guard let urlToDownload = URL(string: videoURLStringToDownload) else { return }
urlToDownload.saveVideo(success: { (isSaved,url) in
guard let videoURL = url, isSaved else { return }
let player = AVPlayer(url: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player?.play()
}
})
import AVKit for playing videos through AVPlayerViewController
import Photos and PhotosUI for saving Video with PHAsset.
Hope it helps!

after picking up images i want to delete photos from photoStore. Out of ideas noew

for asset in assets{
let phasest = asset.originalAsset
print(phasest?.mediaType)
let currentPhasset = PHAsset.fetchAssetsWithMediaType(phasest?.mediaType, options: nil)
asset.fetchFullScreenImageWithCompleteBlock({ (image, info) -> Void in
orignalImages.append(image!)
print (info)
let fetchResult = currentPhasset
let lastAsset: PHAsset = fetchResult[1] as! PHAsset
print(fetchResult)
let arrayToDelete = NSArray(object: lastAsset)
PHPhotoLibrary.sharedPhotoLibrary().performChanges( {
PHAssetChangeRequest.deleteAssets(arrayToDelete)},
completionHandler: {
success, error in
NSLog("Finished deleting asset. %#", (success ? "Success" : error!))
})
i m using dkimagecontroller to pick images. in this code in i can delete the first photo as i pass index 1 in fetch result . if i pass any bigger number it is deleting empty data. So how can i delete selected image??i
well . i found easy fix for that. Hope it helps someone
for asset in assets{
let phasest = asset.originalAsset
asset.fetchFullScreenImageWithCompleteBlock({ (image, info) -> Void in
orignalImages.append(image!)
if (phasest != nil) {
let arrayToDelete = NSArray(object: phasest!)
PHPhotoLibrary.sharedPhotoLibrary().performChanges( {
PHAssetChangeRequest.deleteAssets(arrayToDelete)},
completionHandler: {
success, error in
NSLog("Finished deleting asset. %#", (success ? "Success" : error!))
})
}

Getting the URL of picture taken by camera with Photos Framework

I have an app that uses a UIImagePickerController to retrieve pictures both from camera and from the photos library.
In the image picker delegate I only want to save the NSURL (UIImagePickerControllerReferenceURL) of the picked image to save memory. When the user needs to see the image later on, I load it with PHCachingImageManager directly from the photos library.
Now - this whole thing works great with pictures the user chooses from the library, but not with pictures directly taken by camera (since there is no URL). I am currently trying to save the picture with PHAsset, but I have no idea how to get the NSURL of the save picture.
This is what I've been up to:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
picker.dismissViewControllerAnimated(true, completion: nil)
let pickedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
if picker.sourceType == .Camera
{
// When taking a picture with the camera, store it in the user roll
PHPhotoLibrary.sharedPhotoLibrary().performChanges(
{ () -> Void in
// save the image
PHAssetCreationRequest.creationRequestForAssetFromImage(pickedImage)
// TODO how to get the asset url
}, completionHandler:
{ (finished, error) -> Void in
if (finished)
{
}
}
)
}
else
{
let pickedImageUrl: NSURL? = info[UIImagePickerControllerReferenceURL] as? NSURL
currentImageUrl = pickedImageUrl
currentImage = pickedImage
toggleImageInfoView(true)
toggleMapState(true)
}
}
Any ideas how to get the url of the saved picture?
Best,
Georg
UPDATE: Seems like I found an answer to this Problem.
Step 1: I save the image to the camera
UIImageWriteToSavedPhotosAlbum(image.image, self, #selector(cameraImageSavedAsynchronously), nil)
this is done asynchronously, so make sure to set a selector when operation has finished.
Step 2: When operation has completed, I do the following:
func fetchLastImage(completion: (localIdentifier: String?) -> Void)
{
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.fetchLimit = 1
let fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: fetchOptions)
if (fetchResult.firstObject != nil)
{
let lastImageAsset: PHAsset = fetchResult.firstObject as! PHAsset
completion(localIdentifier: lastImageAsset.localIdentifier)
}
else
{
completion(localIdentifier: nil)
}
}
I fetch the last image in camera roll with PHAsset and save the local identifier of the image. This is not an URL, but a unique identifier which does not change. This way, you can access the saved image perfectly.
Hope this helps others!
I agree with you.
but, if the Image's Exif has the date of the earlier .
let fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: fetchOptions)
fetchResult.firstObject
fetchResult.firstObject is not the one you just saved.
maybe you can modify fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false) to key: "modificationDate"
BTW, I found an other way:
__block PHObjectPlaceholder *placeholderAsset = nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
newAssetRequest.location = location;
newAssetRequest.creationDate = [NSDate date];
placeholderAsset = newAssetRequest.placeholderForCreatedAsset;
} completionHandler:^(BOOL success, NSError *error) {
if(success){
PHAsset *asset = [self getAssetFromlocalIdentifier:placeholderAsset.localIdentifier];
completionBlock(asset, YES);
} else {
completionBlock(nil, NO);
}
}];
can get the newly PHAsset.
Ive updated the answer to include returning any asset type, as well as simpler/cleaner way of returning the asset.
Theres no need to a competition handler.
func fetchLastAsset() -> PHAsset? {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.fetchLimit = 1
let fetchResult = PHAsset.fetchAssets(with: fetchOptions)
return fetchResult.firstObject
}

Deleting PHAssetCollection (Swift)

I created an PHAssetCollection to house my photos for my app, and it works fine. However, I am trying to have it so the user can delete the PHAssetCollection when they press a button. How do I go about deleting the entire AssetCollection ("App Folder") that I created in the following code?
Code to create PHAssetCollection:
let albumName = "App Folder"
//Check if the folder exists, if not, create it
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", albumName)
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let first_Obj:AnyObject = collection.firstObject{
//found the album
self.albumFound = true
self.assetCollection = first_Obj as! PHAssetCollection
}else{
//Album placeholder for the asset collection, used to reference collection in completion handler
var albumPlaceholder:PHObjectPlaceholder!
//create the folder
NSLog("\nFolder \"%#\" does not exist\nCreating now...", albumName)
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(albumName)
albumPlaceholder = request.placeholderForCreatedAssetCollection
},
completionHandler: {(success:Bool, error:NSError!)in
if(success){
println("Successfully created folder")
self.albumFound = true
if let collection = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([albumPlaceholder.localIdentifier], options: nil){
self.assetCollection = collection.firstObject as! PHAssetCollection
}
}else{
println("Error creating folder")
self.albumFound = false
}
})
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
PHAssetCollectionChangeRequest.deleteAssetCollections([self.deleteTarget])
}, completionHandler: nil)
There's a class method in PHAssetCollectionChangeRequest called deleteAssetCollections: which does just that: requests that specific asset collections be deleted. Looking at the documentation it seems you can just call this with an array of PHAssetCollections like so:
PHAssetCollectionChangeRequest.deleteAssetCollections(self.assetCollection)
just made it easy to use. hope it helps :
Here's function to delete custom album programmatically with error handeling
func deleteAlbum(albumName: String){
let options = PHFetchOptions()
options.predicate = NSPredicate(format: "title = %#", albumName)
let album = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: options)
// check if album is available
if album.firstObject != nil {
// request to delete album
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.deleteAssetCollections(album)
}, completionHandler: { (success, error) in
if success {
print(" \(albumName) removed succesfully")
} else if error != nil {
print("request failed. please try again")
}
})
}else{
print("requested album \(albumName) not found in photos")
}
}
How to Use -
deleteAlbum(albumName: "YourAlbumName")

Resources