2016-01-06 46 views
2

我試圖符合在NSDate添加到ForwardIndexType其實如此,我可以做一個Range<NSDate>,爲了做到這一點,我必須從_Incrementable實現public func successor() -> Self如何符合加入_Incrementable在NSDate的

我的實現非常簡單,目的是說明成功的日期是一秒之後的日期,這不是在這裏問的。

extension NSDate: ForwardIndexType { 
    public func successor() -> Self { 
     return NSDate(timeInterval: 1, sinceDate: self) 
    } 
} 

我得到的錯誤是

Cannot convert return expression of type ' NSDate ' to return type ' Self '

我已經嘗試添加as Selfas! Self但是編譯器不允許我因爲從NSDateSelf在這種情況下總是成功轉換。替換SelfNSDate也沒有辦法。

我該如何正確地做到這一點?

+2

接班人會是什麼:總是第二?或一天?毫秒?您只應將具有自然後繼的構造的後繼定義爲整數。 1之後是2.即對於不存在這樣的自然後繼者的浮體。此外,對於某個時間點,沒有天然的繼任者,並且NSDate正在代表這樣一個觀點,因此它不應該有一個好的繼任者。 – vikingosegundo

+0

正如我在我的問題中所述,即使我認爲這是一個非常有效的討論,我會認爲它應該總是一秒鐘。 – fpg1503

+0

但爲什麼它需要成爲後繼方法。只需創建'advanceByOneSecond()'或更好'advanceBy(_time,inUnit:NSCalendarUnit)'。 – vikingosegundo

回答

2

正如幾位評論所說,即使可能,你也不應該這樣做。 NSDate沒有邏輯「下一個」。創造一個風險的副作用。公共類型的擴展是全球性的。如果你說「下一個日期是下一秒」而另一個擴展說「下一個日期是第二天?」會發生什麼?兩者同樣合理(同樣不正確)。如果其他人也這樣做,請勿添加可能與不同含義相沖突的擴展名。

你說你的目標是:

I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values

這是一點問題都沒有。首先,如你所說,你希望「在給定的時間間隔內」。優秀。這是一個ClosedInterval<NSDate>。爲了得到那個,NSDate必須是可比較的。添加該擴展沒有任何問題。任何合理實施它的人都必須以這種方式實施。

extension NSDate: Comparable {} 

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

現在您要將其轉換爲積分秒範圍,而不是日期範圍。然後將該範圍內的元素進行混洗,取出第一個值,並將其映射回日期。我們假設你已經有Nate Cook的shuffle code

func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate> 
    (interval: DateInterval, count: Int) -> [NSDate] { 
    // For convenience we're going to assume that the range is no larger than 68 years. 
    // If you need ranges larger than that, it's a bit more work and probably the subject 
    // of a second question. (See https://stackoverflow.com/a/34388108/97337 for the basis.) 
    let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start)) 

    let offsets = (0...intervalSize).shuffle() 

    return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }.prefix(count)) 
} 

你甚至可以用它來與.....<來定義的時間間隔:

// 100 second-interval dates from the last hour 
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100) 
    .forEach { print($0) } 

注意,這個算法是有點慢和內存密集型如果n比秒數顯着較小在間隔。我們必須創建可能是一個相當龐大的一系列數字,以便按照您的要求進行操作。如果你不關心重複,那麼這一切都簡單得多:

let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start)) 

return (1...count).map { _ in 
    let offset = arc4random_uniform(intervalSize) 
    return interval.start.dateByAddingTimeInterval(Double(offset)) 
} 

如果間隔,遠遠高於n大,那麼重複的機率很低。如果你仍然想避免重複,而無需分配是巨大的初始陣列,考慮Set

func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate> 
    (interval: DateInterval, count: Int) -> [NSDate] { 
     let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start)) 

     var offsets = Set<UInt32>() 
     while offsets.count < count { 
      offsets.insert(arc4random_uniform(intervalSize)) 
     } 

     return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) } 
} 

一個Set的代價是,這種做法是非常緩慢的,如果n類似幅度的要數在間隔內秒數。在那種情況下,洗牌效率會更高。

+0

謝謝,你的回答非常徹底,並以出色的方式解決了我的問題。 – fpg1503

0

試試這個,改變SelfNSDate,除去ForwardIndexType協議

使用代碼一樣,

var date = NSDate() 
date = date.successor() 

let newDate = date.successor() 

ForwardIndexType協議,有喜歡,advancedBy:distanceTo:方法,要實現方法successor,只是實現協議_Incrementable。這將工作。

+1

然後,如果不符合協議'_Incrementable':_Error:非終結類'NSDate'中的方法'successor()'必須返回'Self'以符合協議'_Incrementable'_ – dfri

+0

我已經獲得了mac和xcode ,嘗試過,請檢查我編輯的答案 –

+0

檢查編輯的答案,工作正常。 –