What’s up?
In my previous post I told you about the fix for compilation error in case optimization was enabled. And as I’ve already mentioned, I still haven’t succeeded in improving app’s performance. Today I’ll tell you how I found the reason for the poor performance and how I fixed it.
In my project, the list of files sorted by name should be displayed. When lists are sorted via string comparator, the performance is good enough. But if the files are sorted like in the Finder, performance drops dramatically in case array contains a big amount of elements.
For example, let’s take the contents of ~/Library/Preferences folder (1000 files in total) and sort the list with this code:
filesArray.sort({ (item1:NSURL, item2:NSURL) -> Bool in
let comparisonOptions:NSStringCompareOptions = NSStringCompareOptions.CaseInsensitiveSearch | NSStringCompareOptions.NumericSearch | NSStringCompareOptions.WidthInsensitiveSearch | NSStringCompareOptions.ForcedOrderingSearch;
var str1:String = item1.path!.lastPathComponent
var str2:String = item2.path!.lastPathComponent
var res = str1.compare(str2, options: comparisonOptions, range: str1.startIndex ..< str1.endIndex, locale: NSLocale.currentLocale())
return res == NSComparisonResult.OrderedAscending
})
When using Xcode6 beta6 with the enabled optimization, it takes 5 seconds to sort the files. (Just to compare, it took about several minutes in beta5.) As you see, files sorting speed cannot be called acceptable anyway.
I decided to compare the sorting time of the method described above with the time of this method:
filesArray.sort( { $0.path!.lastPathComponent > $1.path!.lastPathComponent })
And it suddenly dawned on me that the problem could lie in calling the following Objcetive-C method from Swift too often:
- compare:options:range:locale:
I decided to sort array using methods of NSArray class.
var nsFilesArray = filesArray as NSArray
nsFilesArray = nsFilesArray.sortedArrayUsingComparator({(item1:AnyObject!, item2:AnyObject!) -> NSComparisonResult in
let comparisonOptions:NSStringCompareOptions =
NSStringCompareOptions.CaseInsensitiveSearch |
NSStringCompareOptions.NumericSearch |
NSStringCompareOptions.WidthInsensitiveSearch |
NSStringCompareOptions.ForcedOrderingSearch;
var str1:String = (item1 as NSURL).path!.lastPathComponent
var str2:String = (item2 as NSURL).path!.lastPathComponent
return str1.compare(str2, options: comparisonOptions, range: str1.startIndex ..< str1.endIndex, locale: NSLocale.currentLocale())
})
filesArray = nsFilesArray as Array
These changes result in sorting within only 0,02 seconds even when optimization is disabled. That is what I call adequate performance.
Note: This might prove to be not the best solution actually, as I had to call NSArray method.
Hope to come back to this issue after Xcode6 release. But at the moment, that is the most satisfactory resolving of the problem.
BTW, see in the last listing how closure can be easily transferred into the ordinary Objective-C method!
Subscribe here:
https://www.facebook.com/develtima
https://twitter.com/develtima