2016-10-12 10 views
1

私はすぐに始まるthisの素晴らしい例からカレンダーを作ろうとしています。これまでのところ、私はグリッドとすべての補助的なビューをカスタマイズするために管理しましたUICollectionViewLayout。問題は、カレンダーにイベントを追加しようとしているときです。日行とカレンダーの両方が同じNSMutableDictionaryにあり、この形式を使用して日付(文字列)を表すキーが2016-10-12です。目的のCコードははSwiftで使用できる@distinctUnionOfObjectsですか?

-(void)groupEventsBySection{ 
    //toDeviceTimezoneDateString simply take a Date and make a string 
_eventsBySection = [mEvents groupBy:@"StartDate.toDeviceTimezoneDateString"].mutableCopy; 
    // after groupBy is performed _eventsBySection contains only those keys found in mEvents with inside an array of objects { 
    // "2016-10-12" =  (
    // "<MSEvent: 0x60000004a680>", 
    // "<MSEvent: 0x60000004a380>"); 
    // "2016-10-13" =  (
    // "<MSEvent: 0x600000049b10>"); 
    // "2016-10-17" =  (
    // "<MSEvent: 0x600000049fc0>"); 
    // } 

NSDate* date = [NSDate today:@"device"]; // today's date 
if(self.daysToShow == 1 && _eventsBySection.count == 1){ 
    date = [NSDate parse:_eventsBySection.allKeys.firstObject]; 
} 
//here it adds the remaining "daysToShow" if the key doesn't already exist in the MutableDictionary. 
for(int i = 0; i< self.daysToShow; i++){ 
    if(![_eventsBySection.allKeys containsObject:date.toDeviceTimezoneDateString]){ 
     [_eventsBySection setObject:@[] forKey:date.toDeviceTimezoneDateString]; 
    } 
    date = [date addDay]; // this just add one day to date 
} 
} 

です。これまではかなり明確です。

- (NSDictionary*)groupBy:(NSString*)keypath{ 
return [self groupBy:keypath block:^NSString *(id object, NSString *key) { 
    return key; 
}]; 
} 

- (NSDictionary*)groupBy:(NSString*)keypath block:(NSString*(^)(id object, NSString* key))block{ 
    NSMutableDictionary *result = [NSMutableDictionary new]; 
    NSString* finalKeypath = [NSString stringWithFormat:@"%@[email protected]",keypath]; 
    NSArray *distinct = [self valueForKeyPath:finalKeypath]; 

    [distinct each:^(NSString* value) { 
     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", keypath,value]; 
     NSArray *objects  = [self filteredArrayUsingPredicate:predicate]; 
     [result setObject:objects forKey:block(objects[0],value)]; 
    }]; 
     return result; 
} 

- (NSDictionary*)expand:(NSString*)keypath{ 
    return [self expand:keypath unique:NO]; 
} 

これまでのところ、これは私が迅速に行われたものである:私はObjective Cの中groupBy機能を変更しようとすると、問題がある

私は元のコードでMSEventあり、このクラスを持っています

class Event : NSObject { 

var title:String? 
var location:String? 
var startTime:Date? 
var endTime:Date? 
var duration:Int? 
var subtitle:String? 

init(startTime: Date, duration: Int, title: String, subtitle: String) { 
    super.init() 
    self.startTime = startTime 
    self.duration = duration 
    self.title = title 
    self.subtitle = subtitle 

} 

私はいくつかの偽のイベントを作成します。

override func viewDidLoad() { 
     let today = Date() 
     let event1 = Event(startTime: today, duration: 60, title: "prova", subtitle: "HEllo") 
     let event2 = Event(startTime: today, duration: 60, title: "prova", subtitle: "HEllo") 
     let event3 = Event(startTime: today.dateByAddingDays(days: 1), duration: 60, title: "prova", subtitle: "HEllo") 

     var array:[Event] = [] 
     array.append(event1) 
     array.append(event2) 
     array.append(event3) 

     calendarView.setEvents(events: array) 
} 

func setEvents(events:[Event]){ 

    mEvents = events as NSArray  
    print(mEvents) 
    //this right now returns the 3 event objects I added: 
    // (
    // "<myapp.Event: 0x60800032ba40>", 
    // "<myapp.Event: 0x60800032bae0>", 
    // "<myapp.Event: 0x60800032bcc0>" 
    // ) 
    self.forceReload(reloadEvent: true) //force reload eventually call the groupEventsBy days 
} 


func groupEventsByDays(){ 
    // of course everything works without the next line of code 
    eventsBySection = mEvents.groupBy(keypath: "startTime").mutableCopy() as! NSMutableDictionary 
    let dateFormatter = DateFormatter() 
    dateFormatter.dateFormat = "yyyy-MM-dd" 
    var date = dateFormatter.date(from: "2016-10-01") 
        // right now daysToShow is equal to 30 
      for _ in 0..<daysToShow{ 

     eventsBySection.setObject([], forKey: self.setFormatDate(date: date!) as NSCopying) 


     date = self.addDay(date: date!) 

    } 
} 

ここに問題があります。これは私の拡張です。それは私が(ただし明確な)すべての日付を得ることができたが、私は見当がつかないmap

このような
 let startDate = array.map ({ $0.startTime }) 

を使用しようとしましたエラーthis class is not key value coding-compliant for the key startTitle.distinctUnionOfObjects.self.' でクラッシュし 延長にNSArray {

func groupBy(keypath:NSString)->NSDictionary{ 

     return self.groupBy(keypath: keypath, block: { (object, key) -> NSString in 
      return key 
     }) 
    } 

    func groupBy(keypath:NSString,block:@escaping ((_ object: Any, _ key:NSString)-> NSString))-> NSDictionary{ 

     let result:NSMutableDictionary = NSMutableDictionary() 

     let finalKeypath = String.localizedStringWithFormat("%@.distinctUnionOfObjects.self", keypath) 
     let distinct:NSArray = self.value(forKey: finalKeypath) as! NSArray 

     (distinct as AnyObject).each(operation: { (value) in 
      let predicate = NSPredicate(format: "%K = %@", keypath,value as! CVarArg) 
      let objects = self.filtered(using: predicate) 
      result.setObject(objects, forKey: (block(objects[0], value as! NSString))) 

      }) 

     return result; 
    } 

    func each(operation:@escaping ((_ object: AnyObject)-> Void)){ 

     self.enumerateObjects({ (object, idx, stop) in 
      operation(object as AnyObject) 
     }) 

    } 
} 

swiftを使用して上記のコードに示されているのと同じ結果を得る方法。

+0

これはうまくいくはずですが、そのキーパスがNSObjectのサブクラスを照会していて、Objective-Cランタイムに表示されているプロパティをstartTitleしているところで 'self'ですか? (つまりObjective-Cと互換性のあるタイプのものです - その名前に基づいて 'String'を推測していますか?) – mz2

+0

ああ、それはNSArray拡張であったので、実際には' self'です。しかし、 'startTitle'に関する質問は残っています。 – mz2

答えて

1

最後に、上記の目的のCコードが行うことを、@distinctUnionOfObjects.selとしました。私は本当にこれをやっているエレガントな方法ではないと確信していません。すべてのコメントやより良い答えは大歓迎です。

extension Collection { 
    func find(predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.Iterator.Element? { 
     return try index(where: predicate).map({self[$0]}) 
    } 
} 

override func viewDidLoad() { 
    super.viewDidLoad() 

let event1 = Event(startTime: today!, duration: 60, title: "prova", subtitle: "HEllo") 
let event2 = Event(startTime: (today?.dateByAddingDays(days: 5))!, duration: 60, title: "prova", subtitle: "HEllo") 
let event3 = Event(startTime: (today?.dateByAddingDays(days: 1))!, duration: 60, title: "prova", subtitle: "HEllo") 
let event4 = Event(startTime: todayLater!, duration: 60, title: "prova", subtitle: "HEllo") 

var array:[Event] = [] 
array.append(event1) 
array.append(event2) 
array.append(event3) 
array.append(event4) 

// I create an array with all the date/startTime 
let startTime = array.map ({ $0.startTime }) 

let dict:NSMutableDictionary = [:] 

    for date in startTime { 
      //find the objects for that date 
      let object = array.find(predicate: {$0.startTime?.toDeviceDateString() == date?.toDeviceDateString()}) 
      //check if that key/date exist in the dictionary 
     if var val:[Event] = dict[(date?.setFormatDate())!] as! [Event]? { 
       //if it does I simply add the object to the array 
      val.append(object!) 
      dict.setObject(val, forKey: date?.setFormatDate() as! NSCopying) 

     } else { 
      print("key is not present in dict") 
      //otherwise I add a new array with that object inside for the date/key 
      dict.setObject([object], forKey: date?.setFormatDate() as! NSCopying) 
     } 


    } 

    calendarView.setEvents(events: dict) 
} 

func setEvents(events:NSMutableDictionary){ 
//slots events hold the events objects 
slotEvents = events 
self.forceReload(reloadEvent: true) 

} 


func groupEventsByDays(){ 


let dateFormatter = DateFormatter() 
dateFormatter.dateFormat = "yyyy-MM-dd" 
var date = dateFormatter.date(from: "2016-10-01") 

for _ in 0..<daysToShow{ 

    if let val:[Event] = slotEvents[(date?.setFormatDate())!] as! [Event]? { 

     eventsBySection.setObject(val, forKey: date?.setFormatDate() as! NSCopying) 

    }else{ 

     eventsBySection.setObject([], forKey: date?.setFormatDate() as! NSCopying) 

    } 

    date = self.addDay(date: date!) 

} 
print("after\(eventsBySection)") 
    //Which print 
    //{ 
//"2016-10-01" =  (
//); 
//"2016-10-02" =  (
//); 
// "2016-10-03" =  (
//  "Optional(<myapp.Event: 0x6000001242e0>)", 
//  "<myapp.Event: 0x6000001242e0>" 
// ); 
// "2016-10-04" =  (
//  "Optional(<myapp.Event: 0x600000124600>)" 
// ); 
// "2016-10-05" =  (
// ); 
// "2016-10-06" =  (
// ); 
// "2016-10-07" =  (
// ); 
// "2016-10-08" =  (
//  "Optional(<myapp.Event: 0x600000124240>)" 
// ); 
// "2016-10-09" =  (
// ); 
    //.... and so on up to 30 days 

} 
関連する問題