I'm trying to create a simple controller in swift that allows me to collect photos from the library taken between two precise dates, e.g February the 15th 2015, an February the 18th 2015. During my searches I read about the Photo Framework of iOS, and I'd like to know if there's a simple way to query the photo library with such a framework based on the dates mentioned above. I'd like also to get images metadata like geo location for example. It'd be great if I could do that with the same framework Thanks for your answers
-
did u look into http://stackoverflow.com/questions/9290929/how-to-get-the-latest-photo-in-iphone-library ? – Teja Nandamuri Jan 25 '16 at 21:34
-
2@Mr.T That answer's dated. It's better to now use the Photos framework in place of the Assets Library framework. – Lyndsey Scott Jan 25 '16 at 21:49
2 Answers
To collect the photos between two dates, first you need to create NSDate
s representing the start and end of the date range. Here's a NSDate
extension (from https://stackoverflow.com/a/24090354/2274694) that can create the dates from their string representations:
extension NSDate {
convenience
init(dateString:String) {
let dateStringFormatter = NSDateFormatter()
dateStringFormatter.dateFormat = "MM-dd-yyyy"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let d = dateStringFormatter.dateFromString(dateString)!
self.init(timeInterval:0, sinceDate:d)
}
}
Then use the NSDate
s to create a predicate for the PHFetchResult
's PHFetchOptions
.
import Photos
class ViewController: UIViewController {
var images:[UIImage] = [] // <-- Array to hold the fetched images
override func viewDidLoad() {
fetchPhotosInRange(NSDate(dateString:"04-06-2015"), endDate: NSDate(dateString:"04-16-2015"))
}
func fetchPhotosInRange(startDate:NSDate, endDate:NSDate) {
let imgManager = PHImageManager.defaultManager()
let requestOptions = PHImageRequestOptions()
requestOptions.synchronous = true
requestOptions.networkAccessAllowed = true
// Fetch the images between the start and end date
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate, endDate)
images = []
if let fetchResult: PHFetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) {
// If the fetch result isn't empty,
// proceed with the image request
if fetchResult.count > 0 {
// Perform the image request
for var index = 0 ; index < fetchResult.count ; index++ {
let asset = fetchResult.objectAtIndex(index) as! PHAsset
imgManager.requestImageDataForAsset(asset, options: requestOptions, resultHandler: { (imageData: NSData?, dataUTI: String?, orientation: UIImageOrientation, info: [NSObject : AnyObject]?) -> Void in
if let imageData = imageData {
if let image = UIImage(data: imageData) {
// Add the returned image to your array
self.images += [image]
}
}
if self.images.count == fetchResult.count {
// Do something once all the images
// have been fetched. (This if statement
// executes as long as all the images
// are found; but you should also handle
// the case where they're not all found.)
}
})
}
}
}
}
}
Updated for Swift 3:
import UIKit
import Photos
class ViewController: UIViewController {
var images:[UIImage] = [] // <-- Array to hold the fetched images
override func viewDidLoad() {
let formatter = DateFormatter()
formatter.dateFormat = "MM-dd-yyyy"
fetchPhotosInRange(startDate: formatter.date(from: "04-06-2015")! as NSDate, endDate: formatter.date(from: "04-16-2015")! as NSDate)
}
func fetchPhotosInRange(startDate:NSDate, endDate:NSDate) {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.isNetworkAccessAllowed = true
// Fetch the images between the start and end date
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate, endDate)
images = []
let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
// If the fetch result isn't empty,
// proceed with the image request
if fetchResult.count > 0 {
// Perform the image request
for index in 0 ..< fetchResult.count {
let asset = fetchResult.object(at: index)
imgManager.requestImageData(for: asset, options: requestOptions, resultHandler: { (imageData: Data?, dataUTI: String?, orientation: UIImageOrientation, info: [AnyHashable : Any]?) -> Void in
if let imageData = imageData {
if let image = UIImage(data: imageData) {
// Add the returned image to your array
self.images += [image]
}
}
if self.images.count == fetchResult.count {
// Do something once all the images
// have been fetched. (This if statement
// executes as long as all the images
// are found; but you should also handle
// the case where they're not all found.)
print(self.images)
}
})
}
}
}
}

- 1
- 1

- 37,080
- 10
- 92
- 128
-
@Lindsey damn i need to get some sleep... got confused between all the articles i had opened on SO – Vincent Rolea Jan 26 '16 at 15:07
-
this throws massive errors in Swift 3. Maybe you need to update the answer – George Asda Nov 25 '16 at 15:34
-
@GeorgeAsda I updated the code to Swift 3 but didn't see any errors... Which errors were you referring to? – Lyndsey Scott Nov 27 '16 at 16:16
-
The previous code snippet threw errors in Swift 3. The updated one I have not tested. – George Asda Nov 27 '16 at 17:46
-
@GeorgeAsda Were they errors? Meaning did you convert the code on your own, run the code, and did the build produce errors? Or do you just mean that the code wouldn't compile because it was a different version of Swift? You have to convert to whatever version of swift code is in to whatever version of swift you're using, if that's what you mean... Otherwise the code wouldn't be compatible... – Lyndsey Scott Nov 27 '16 at 17:54
-
As I said in my comment. The previous version of code did not compile in Swift 3. I have updated the code myself and seemed to be working ok but did not use it at the end. I was going to give a new updated answer for Swift 3 but since I wasn't using it I thought it would be best if you updated your own answer. Makes sense? – George Asda Nov 27 '16 at 22:39
-
@GeorgeAsda It didn't compile in Swift 3 because it wasn't in Swift 3. Strange reason for a downvote is all I'm saying... (Not that I mind at all and no need to change that at all. But just was confused why someone would downvote an answer in one language when they try to use a compiler that requires another language.) – Lyndsey Scott Nov 27 '16 at 22:44
-
-
Among the other errors, the `NSPredicate` is wrong: it should be using <= and >= instead of < and > – xaphod Mar 23 '19 at 23:38
First of all I want to say thanks to 'Lyndsey Scott' for such a wonderful code she did. It's really helpful. May be returning errors to few compiler as those are latest one and the code need to be updated a little. So Here I am giving the latest updated code to make Lyndsey's code error free for latest compiler for Swift 4.0 or above.
extension NSDate {
convenience
init(dateString:String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "MM-dd-yyyy"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale?
let d = dateStringFormatter.date(from: dateString)!
self.init(timeInterval: 0, since: d)
}
}
Then use the NSDates to create a predicate for the PHFetchResult's PHFetchOptions.
import UIKit
import Photos
class ViewController: UIViewController {
var images:[UIImage] = [] // <-- Array to hold the fetched images
override func viewDidLoad() {
super.viewDidLoad()
fetchPhotosInRange(startDate: NSDate(dateString:"07-15-2018"), endDate: NSDate(dateString:"07-31-2018"))
}
func fetchPhotosInRange(startDate:NSDate, endDate:NSDate) {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.isNetworkAccessAllowed = true
// Fetch the images between the start and end date
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "creationDate > %@ AND creationDate < %@", startDate, endDate)
images = []
if let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions) {
// If the fetch result isn't empty,
// proceed with the image request
if fetchResult.count > 0 {
// Perform the image request
for (index) in 0 ..< fetchResult.count {
// for var index = 0 ; index < fetchResult.count ; index++ {
let asset = fetchResult.object(at: index)
// Request Image
imgManager.requestImageData(for: asset, options: requestOptions, resultHandler: { (imageData, str, orientation, info) -> Void in
if let imageData = imageData {
if let image = UIImage(data: imageData) {
// Add the returned image to your array
self.images += [image]
}
}
if self.images.count == fetchResult.count {
// Do something once all the images
// have been fetched. (This if statement
// executes as long as all the images
// are found; but you should also handle
// the case where they're not all found.)
}
})
}
}
}
print("images ==>\(images)")
}
Happy coding..

- 51
- 1
- 2