Sorting Files by Modified Date in iOS
When working with file systems in iOS, it’s not uncommon to need to sort or filter files based on certain criteria. In this article, we’ll explore how to sort files by modified date using NSFileManager
and NSURL
.
Understanding File System Properties
Before we dive into the code, let’s take a brief look at what properties can be retrieved from the file system. The NSURLContentModificationDateKey
constant is used to retrieve information about when a file was last modified on disk.
When you create an instance of NSURL
, it contains metadata about the file or directory, including its content modification date. This date is represented as an NSDate
object and can be retrieved using the -getResourceValue:forKey:error:
method.
Retrieving File Contents and Modification Dates
To sort files by modified date, we need to retrieve the contents of a directory and then extract the file names along with their corresponding modification dates. We’ll use NSFileManager
to do this.
{< highlight language="objc" >}
- (void)sortFilesByModifiedDate {
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *files = [manager contentsOfDirectoryAtURL:[[NSBundle mainBundle] resourceURL]
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:nil
error:nil];
NSMutableArray *dates = [NSMutableArray array];
for (NSURL *f in files) {
NSDate *d = nil;
if ([f getResourceValue:&d forKey:NSURLContentModificationDateKey error:nil]) {
[dates addObject:d];
}
}
// Sort the dates
NSArray *sortedDates = [dates sortedArrayUsingComparator:^NSComparisonResult(id x, id y) {
return [x compareYieldSelf:y options:NSDirectionForward comparativeTo:]
== NSOrderedDescending ? @YES : @NO;
}];
// Print the sorted file names and modification dates
for (int i = 0; i < sortedDates.count; i++) {
NSDate *date = [sortedDates objectAtIndex:i];
NSString *fileName = [f pathComponents].lastObject;
NSLog(@"File: %s Modified Date: %@", fileName, date);
}
}
{/ highlight }
In the code above, we create an instance of NSFileManager
and use its -contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:
method to retrieve an array of URLs representing files in a directory. We then extract the modification dates from each URL using -getResourceValue:forKey:error:
.
We store these dates in an NSMutableArray
called dates
. After we’ve populated this array, we sort it using the sortedArrayUsingComparator:
method.
Finally, we print out the sorted file names and their corresponding modification dates to the console.
Using a Comparator Block
When sorting arrays of dates, you’ll often want to compare two values (in this case, dates). To do this in Objective-C, you can create a comparator block that takes two values as arguments and returns an integer value indicating their comparison result.
The compareYieldSelf:y:options:
method is used to compare two dates. The NSDirectionForward
option specifies whether the comparison should be done in forward or backward order.
Here’s how you might modify the previous code to use a comparator block:
{< highlight language="objc" >}
- (void)sortFilesByModifiedDate {
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *files = [manager contentsOfDirectoryAtURL:[[NSBundle mainBundle] resourceURL]
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:nil
error:nil];
NSMutableArray *dates = [NSMutableArray array];
for (NSURL *f in files) {
NSDate *d = nil;
if ([f getResourceValue:&d forKey:NSURLContentModificationDateKey error:nil]) {
[dates addObject:d];
}
}
// Sort the dates using a comparator block
NSArray *sortedDates = [dates sortedArrayUsingComparator:^NSComparisonResult(id x, id y) {
NSDate *dateX = x;
NSDate *dateY = y;
if ([dateX compareDateY] == NSOrderedDescending) {
return @YES;
} else if ([dateX compareDateY] == NSOrderedAscending) {
return @NO;
}
// If dates are equal, use a different method to break the tie
if (x != y) {
// Compare files based on their file names
NSString *fileNameX = [f pathComponents].lastObject;
NSString *fileNameY = [f pathComponents].lastObject;
return [fileNameX comparefileNameY options:NSCaseInsensitiveSearch];
}
return NSOrderedSame;
}];
// Print the sorted file names and modification dates
for (int i = 0; i < sortedDates.count; i++) {
NSDate *date = [sortedDates objectAtIndex:i];
NSString *fileName = [f pathComponents].lastObject;
NSLog(@"File: %s Modified Date: %@", fileName, date);
}
}
{/ highlight }
In this modified version of the code, we’ve created a comparator block that compares two dates using their compareDateY
method. If the dates are equal, we break the tie by comparing the file names.
Using Swift
If you’re working with Swift, you can achieve the same result without writing any Objective-C code:
{< highlight language="swift" >}
import Foundation
func sortFilesByModifiedDate() {
let manager = NSFileManager.defaultManager()
var files: [NSURL] = []
do {
let directoryURL = Bundle.main.resourceURL!
let fileNames: [String] = try manager.contentsOfDirectoryAtURL(directoryURL, includingPropertiesForKeys: [.contentModificationDateKey], options: .skipLateCreationError, error: nil)
.map { $0.lastPathComponent }
files = directoryURL.resourceValues(forKeys: [.contentModificationDateKey]).values.map { $0 as? Date }.compactMap { $0 }
} catch {
print("Error retrieving file names: \(error)")
}
// Sort the dates
let sortedDates = files.sorted { $0 > $1 }.map { $0.absoluteValue }
// Print the sorted file names and modification dates
for date in sortedDates {
let fileName = Bundle.main.resourceURL?.lastPathComponent ?? ""
print("File: \(fileName) Modified Date: \(date)")
}
}
{/ highlight }
In this Swift version of the code, we’re using the contentsOfDirectoryAtURL
method to retrieve an array of file names from a directory. We then use the resourceValues(forKeys:)
method to retrieve the modification dates for each file and store them in an array.
We sort the dates by iterating over the array and comparing two values at a time, just like we did with Objective-C code.
Last modified on 2024-01-22