Array of multiple URL's NSFileManager Swift
In this case I think you should use NSURLSession.sharedSession().dataTaskWithURL to do multiple downloads from your links but keeping the download operation asynchronous. You need to add a callback block to it. You should do as follow:
let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as NSURL
let musicArray:[String] = ["http://freetone.org/ring/stan/iPhone_5-Alarm.mp3","http://freetone.org/ring/stan2/Samsung_Galaxy_S4-SMS.mp3","https://www.sounddogs.com/sound-effects/25/mp3/235178_SOUNDDOGS__al.mp3"]
var musicUrls:[NSURL!]!
// create a function to start the audio data download
func getAudioDataFromUrl(audioUrl:NSURL, completion: ((data: NSData?) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(audioUrl) { (data, response, error) in
completion(data: data)
}.resume()
}
// create another function to save the audio data
func saveAudioData(audio:NSData, destination:NSURL) -> Bool {
if audio.writeToURL(destination, atomically: true) {
println("The file \"\(destination.lastPathComponent!.stringByDeletingPathExtension)\" was successfully saved.")
return true
}
return false
}
// just convert your links to Urls
func linksToUrls(){
musicUrls = musicArray
.map() { NSURL(string: $0) }
.filter() { $0 != nil }
}
// create a loop to start downloading your urls
func startDownloadingUrls(){
for url in musicUrls {
let destinationUrl = documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!)
if NSFileManager().fileExistsAtPath(destinationUrl.path!) {
println("The file \"\(destinationUrl.lastPathComponent!.stringByDeletingPathExtension)\" already exists at path.")
} else {
println("Started downloading \"\(url.lastPathComponent!.stringByDeletingPathExtension)\".")
getAudioDataFromUrl(url) { data in
dispatch_async(dispatch_get_main_queue()) {
println("Finished downloading \"\(url.lastPathComponent!.stringByDeletingPathExtension)\".")
println("Started saving \"\(url.lastPathComponent!.stringByDeletingPathExtension)\".")
if self.saveAudioData(data!, destination: self.documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!) ) {
// do what ever if writeToURL was successful
} else {
println("The File \"\(url.lastPathComponent!.stringByDeletingPathExtension)\" was not saved.")
}
}
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println("Begin of code")
linksToUrls()
startDownloadingUrls()
println("End of code")
}
Order a NSURL array
As you want to sort the files by the number you have to parse first the path to achieve it, so let's suppose we have the following array of NSURL
objects:
var urls = [NSURL(string: "file:///path/to/user/folder/2.PNG")!, NSURL(string: "file:///path/to/user/folder/100.PNG")!, NSURL(string: "file:///path/to/user/folder/101.PNG")!, NSURL(string: "file:///path/to/user/folder/1.PNG")! ]
We can use the pathComponents
property to extract an array with all the components in the path for a NSURL
(e.g ["/", "path", "to", "user", "folder", "2.PNG"]
).
If we see we can order the files by the last element in the array that is the filename removing the extension and the dot("."
), in this case the number. Let's see how to do it in the following code:
urls.sortInPlace {
// number of elements in each array
let c1 = $0.pathComponents!.count - 1
let c2 = $1.pathComponents!.count - 1
// the filename of each file
var v1 = $0.pathComponents![c1].componentsSeparatedByString(".")
var v2 = $1.pathComponents![c2].componentsSeparatedByString(".")
return Int(v1[0]) < Int(v2[0])
}
In the above code we use the function sortInPlace
to avoid create another array with the elements sorted, but can you use sort
instead if you want. The another important point in the code is the line return Int(v1[0]) < Int(v2[0])
, in this line we have to convert the number in the string to a real number, because if we compare the two strings "2"
and "100"
the second one is less than greater than because the string are compared lexicographically.
So the the array urls
should be like the following one:
[file:///path/to/user/folder/1.PNG, file:///path/to/user/folder/2.PNG, file:///path/to/user/folder/100.PNG, file:///path/to/user/folder/101.PNG]
EDIT:
The two functions pathComponents
and componentsSeparatedByString
increase the space complexity of the sortInPlace
algorithm, if you can asure that the path for the files always will be the same except it's filename that should be a number you can use instead this code:
urls.sortInPlace { $0.absoluteString.compare(
$1.absoluteString, options: .NumericSearch) == .OrderedAscending
}
I hope this help you.
Storing file names in an array Swift
Here's an example of how it works. This function returns an array of all the files URLs in a directory and all its subdirectories from a given path.
func files(atPath: String) -> [NSURL] {
var urls : [NSURL] = []
let dirUrl = NSURL(fileURLWithPath: atPath)
if dirUrl != nil {
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator? = fileManager.enumeratorAtURL(dirUrl!, includingPropertiesForKeys: nil, options: nil, errorHandler: nil)
while let url = enumerator?.nextObject() as! NSURL? {
if url.lastPathComponent == ".DS_Store" {
continue
}
urls.append(url)
}
}
return urls
}
let allFiles = files("/a/directory/somewhere")
How do I get an array of file names from the iOS File Manager
So, contentsOfFileManager
is going to consist of NSURL
objects. These objects have different fields you can pluck out and use. It looks like you're interested in just the filename so I'd like to draw your attention to the lastPathComponent
field of NSURL. From the docs:
This property contains the last path component, unescaped using the replacingPercentEscapes(using:) method. For example, in the URL file:///path/to/file, the last path component is file.
In other words, calling myNsurl.lastPathComponent
should yield you the filename. So you can loop through the array that's returned by myFileManager.contentsOfDirectory
and get the lastPathComponent
of each one and add them to another array which will contain just the filenames.
FileManager.default.contentsOfDirectory return array with different sorting in iphone 8
NSFileManager
doesn't sort the list of files. But you can do it yourself using sorted
method of array
. The code will look like this:
let files: [String]? = try? FileManager.default.contentsOfDirectory(atPath: self.targetDirectory)
let sortedFiles = files?.sorted()
Sorting an array of NSURL objects by creation date
EDIT : Better answer
If that doesn't work, you will have to write your own comparator block and get the dates to compare manually :(
[cacheContents sortUsingComparator:^ (NSURL *a, NSURL *b) {
// get the two dates
id da = [[a resourceValuesForKeys:[NSArray arrayWithObject:NSURLCreationDateKey] error:nil] objectForKey:NSURLCreationDateKey];
id db = [[b resourceValuesForKeys:[NSArray arrayWithObject:NSURLCreationDateKey] error:nil] objectForKey:NSURLCreationDateKey];
// compare them
return [da compare:db];
}];
(Same disclaimer still applies but I'm not even sure that will compile ;) - you get the idea though!)
Here is my first answer (included here for posterity but mostly it just shows how important it is to read the question properly :)
It's because you're getting an array of NSURL
objects; these don't have a NSURLCreationDateKey
property.
Try this (disclaimer - not 100% it will work)
NSString *key = [NSString stringWithFormat:@"fileAttributes.%@", NSURLCreationDateKey];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:YES];
Your key to sort by is a property of the fileAttributes dictionary which is, in turn, a property of your enumerator.
Finder algorithm for sort by name options
The Finder-like sort order can be realized with localizedStandardCompare
The documentation says:
This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate.
let sortedFileURLs = fileURLs.sorted{ $0.lastPathComponent.localizedStandardCompare($1.lastPathComponent) == .orderedAscending }
Note: lastPathComponent
is preferable over pathComponents.last!
Related Topics
How to Hide the Home Indicator with Swiftui
How to Create an Nsdecimal Without Using Nsnumber and Creating Autoreleased Objects
Get Cellid, Mcc, Mnc, Lac, Signal Strength, Quality and Network in iOS 8.3
Nsinteralinconsistencyexception - Uikeyboardlayoutalignmentview
Get Height of iOS Keyboard Without Displaying Keyboard
Authentication with Wkwebview in Swift
Launchd_Sim Crashing: Could Not Create Temporary State Directory
Ms Excel Type Spreadsheet Creation Using Objective-C for iOS App
Load a .Tmx (Tiled Map) in Sprite Kit
Sending Latitude and Longitude to Server When App Is in Background
Com.Facebook.Sdk Error 2 on iOS
Ios7 App Backward Compatible with iOS5 Regarding Unique Identifier
Type 'String.Index' Does Not Conform Protocol 'Integerliteralconvertible'