如何按照属性值(日期)对包含NSManagedObject子类实例的Swift数组进行排序

45

我正在尝试按照这个问题的被接受的回答中所描述的方法对数组进行排序,但是遇到了Isuru在该答案的评论中提到的问题。即,应该通过实体的"date"属性对数组进行排序的代码会导致编译器抱怨"could not find member 'date'"。

以下是描述实体的NSManagedObject子类:

import Foundation
import CoreData

@objc(Entry)
class Entry: NSManagedObject {

    @NSManaged var date: NSDate
    @NSManaged var reflections: AnyObject
    @NSManaged var contactComment: NSSet
    @NSManaged var person: NSSet

    override func awakeFromInsert() {
        let now:NSDate = NSDate()
        self.date = now;
    }
}

这里是尝试对数组进行排序的代码:

lazy var entries:[Entry] = {
    var days:[Entry] = self.managedObjectContext!.requestEntity("Entry")as [Entry]
    days.sort({$0.date < $1.date})

    var today:Entry = days.last!
    println(today.date)
    return days
}()
请注意,代码的后半部分中,我能够访问并记录一个条目的“日期”属性,并且编译器没有问题。
我的排序语法是否正确?这段代码还有其他问题吗?
5个回答

124

这在一定程度上是由于Swift编译器没有给出有用的错误提示。真正的问题在于NSDate不能直接使用<进行比较。相反,你可以使用NSDatecompare方法,像这样:

days.sort({ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending })

你也可以通过扩展NSDate来实现Comparable协议,以便可以使用<(以及<=>>===)进行比较:

public func <(a: NSDate, b: NSDate) -> Bool {
    return a.compare(b) == NSComparisonResult.OrderedAscending
}

public func ==(a: NSDate, b: NSDate) -> Bool {
    return a.compare(b) == NSComparisonResult.OrderedSame
}

extension NSDate: Comparable { }

注意: 您只需要实现上述所示的<==运算符,然后标准库将提供其余运算符<=>等。

有了这个,您原来的排序函数应该可以正常工作:

days.sort({ $0.date < $1.date })

这对于较小的数据量完美运作,但当你有大量的数据时,加载需要一些时间。是否有更有效率的方法? - nsij22
@nsij22 既然我们在谈论 NSManagedObject,那么这些对象可能来自核心数据存储。在这种情况下,最有效的做法可能是通过核心数据获取请求对数据进行排序。请查看 NSFetchRequest.sortDescriptors: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/index.html#//apple_ref/occ/instp/NSFetchRequest/sortDescriptors - Mike S

16

在Swift 3中,现在日期可以直接进行比较:

let aDate = Date()
let bDate = Date()

if aDate < bDate {

    print("ok")
}

旧Swift: 另一种选择是按日期对象的timeIntervalSince1970属性进行排序,该属性是直接可比较的。

days.sort({$0.date.timeIntervalSince1970 < $1.date.timeIntervalSince1970})

当我需要相同的东西并看到被接受的答案的第一句话时,我才想到它,而这已经比被接受的答案发布的时间晚得多了。 - Fred Faust

10

在Swift 2.1中,使用以下代码行

array.sortInPlace({ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending })

2
最初的回答:更新__Swift 4。
let sortedData = dataToSort.sorted(by: { (obj1, obj2) -> Bool in             
   return obj1.date < obj2. date
})

0
我有一个字典,其键是日期格式,因此我必须按日期对字典进行排序。我将所有键复制到NSArray中,然后使用以下代码对该数组进行排序。
let keys : NSArray = stackedBarDataDict.allKeys // stackedBarDataDict is Data Dictionary
    let dataArray = NSMutableArray()
    for index in 0...(stackedBarDataDict.allKeys.count - 1)
    {
        let dateone = keys.objectAtIndex(index)
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let date1 = dateFormatter.dateFromString(dateone as! String)
        dataArray.addObject(date1!)
    }
    let array : NSArray = (dataArray as NSArray)
        let sortedArray = array.sortedArrayUsingComparator {
        (obj1, obj2) -> NSComparisonResult in

        let p1 = obj1 as! NSDate
        let p2 = obj2 as! NSDate
        let result = p1.compare(p2)
        return result
    }
    print(sortedArray)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接