objective-c构建我自己的自定义日历(nsarraycontroller观察者问题)

时间:2011-02-05 10:04:57

标签: objective-c cocoa

我有一段时间正在构建我自己的日历,因为标准mac cal在布局方面很糟糕。

我所做的是创建一个包含所有日期的NSCollectionView,然后在我的代码中,我将每个日期添加到数组控制器。

到目前为止一切正常并且正在显示!

在这里查看我的ss:http://cl.ly/0Z3a2i12242b2d1m3Z1n

我已经向NSArrayController添加了一个观察者,以便在用户点击日期时知道,这允许我向父类发送消息,告诉它更新cal下的表列表。

我的观察者看起来像这样:

//观察我们的数组 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)对象更改:(NSDictionary *)更改上下文:(void *)context {

if([keyPath isEqualTo:@"selectionIndexes"])
{
    if([[self.arrayController selectedObjects] count] > 0)
    {
        if ([[self.arrayController selectedObjects] count] == 1)
        {
            CalendarDate* obj = [[self.arrayController selectedObjects] objectAtIndex:0];

            if(obj.dateobj != nil)
            {
                if(obj.isOld)
                {
                    self.currentMonth = [self moveMonth:(NSInteger)-1];
                    self.selectedDate = obj.dateobj;

                    [self buildArrayController];
                }
                else {
                    self.selectedDate = obj.dateobj;
                    [self callParent];
                }
            }
        }
    }
}

}

我的一个大问题是,当用户在当前月份之前按下一个日期时(查看SS,iam谈论灰显日期)然后观察者被调用两次,因此我的阵列被送回2个月,我不知道怎么反击这个,现在我已经挣扎了好几天..

我构建阵列控制器的代码如下所示:

- (void) buildArrayController {

    NSLog(@"Building array controller");

    // remove observer, all objects and set selection to -1
    [arrayController removeObserver:self forKeyPath:@"selectionIndexes"];
    [[self.arrayController content] removeAllObjects];
    [self.arrayController setSelectionIndex:-1];

    // getting current month
    NSDateComponents *nowComps = [self.currentCal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit) fromDate:self.currentMonth];

    //  figure out how many days the current month have
    NSRange daysInMonth = [self daysInMonth:self.currentMonth];

    // save current month int for later
    int month = [nowComps month];

    // getting days to add before this month    
    NSDateComponents *weekdayComponents = [self.currentCal components:NSWeekdayCalendarUnit fromDate:self.currentMonth];
    int weekdaysToAdd = (([weekdayComponents weekday] == 1) ? 8 : [weekdayComponents weekday])-2;

    // add days befroe the current month, ie when 1st day of month is on a wednesday f.ex.
    NSDate* lastMonth = [self moveMonth:-1];
    NSRange daysInLastMonth = [self daysInMonth:lastMonth];
    NSDateComponents *lastMonthComps = [self.currentCal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit) fromDate:lastMonth];
    for (int i2 = 0; i2 < weekdaysToAdd; i2++)
    {
        [lastMonthComps setDay:daysInLastMonth.length-weekdaysToAdd+i2+1];

        CalendarDate* obj = [[CalendarDate alloc] init];
        obj.dateobj = [self.currentCal dateFromComponents:lastMonthComps];
        obj.showDot = [coreEditor checkDate:[self.currentCal dateFromComponents:lastMonthComps]];
        obj.textColor = [NSColor lightGrayColor];
        obj.isOld = YES;

        [self.arrayController addObject:obj];

        [obj release];
    }

    // adding actually month dates
    for (int i = 1; i < daysInMonth.length+1; i++)
    {
        [nowComps setDay:i];

        CalendarDate* obj = [[CalendarDate alloc] init];
        obj.dateobj = [self.currentCal dateFromComponents:nowComps];
        obj.showDot = [coreEditor checkDate:[self.currentCal dateFromComponents:nowComps]];

        [self.arrayController addObject:obj];

        [obj release];
    }   

    // add days after the current month 
    NSDate* nextMonthobj = [self moveMonth:1];
    NSDateComponents *nextMonthComps = [self.currentCal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit) fromDate:nextMonthobj];
    for (int i3 = 1; i3 < 7-weekdaysToAdd+1; i3++)
    {
        [nextMonthComps setDay:i3];

        CalendarDate* obj = [[CalendarDate alloc] init];
        obj.dateobj = [self.currentCal dateFromComponents:nextMonthComps];
        obj.showDot = [coreEditor checkDate:[self.currentCal dateFromComponents:nextMonthComps]];
        obj.textColor = [NSColor lightGrayColor];
        obj.isOld = YES;

        [self.arrayController addObject:obj];

        [obj release];  
    }

    // add observer for our array controller
    [self.arrayController addObserver:self
                           forKeyPath:@"selectionIndexes" 
                              options:NSKeyValueObservingOptionNew
                              context:nil];

    // now figure out what object should be selected
    NSDateComponents *selectedComp = [self.currentCal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit) fromDate:self.selectedDate];
    int selectedMonth = [selectedComp month];
    int selectedDay = [selectedComp day]-1;

    if(selectedMonth == month)
    {
        [self.arrayController setSelectionIndex:selectedDay+weekdaysToAdd];
    }
    else {
        [self.arrayController setSelectionIndex:-1];
    }   
}

多数民众赞成!有什么建议吗?

(顺便说一句,如果你有任何想法让我的代码变得更好请告诉我,这是我在Objective-c中的第一个项目:))

更新 我觉得'它不是真正的观察者是问题,但不知何故,当我按下cal中的前一个日期并且我的方法重建数组时,它会重新发送/点击更新项目时的下一个视图,是不是htis做塞内斯?我可以临时禁用集合视图上的点击事件吗?

UPDATE2 好的,我尝试添加这个

                    self.selectedDate = obj.dateobj;
                    self.currentMonth = [self moveMonth:(NSInteger)-1];

                    [self.collectionView setSelectable:NO];

                    [self buildArrayController];

                    [self.collectionView setSelectable:YES];

删除collecitonview的选择但它不起作用,所以它必须是shomehow被调用两次的观察者..:t

1 个答案:

答案 0 :(得分:0)

看起来您的观察者将被调用两次:

  • 用户选择当前月份之前的新日期。这会导致“selectionIndexes”发生变化,并导致调用您的观察者方法。
  • 在buildArrayController中,您将自己移除为观察者,进行更改然后以观察者身份重新激活自己。在重新添加自己作为观察者之后,在数组控制器上调用'setSelectionIndex',这会导致第二次观察回调。

在第二个回调中,obj.isOld将为false,所以幸运的是你没有进入这个无限循环。尝试将呼叫转移到

[self.arrayController addObserver:self
                       forKeyPath:@"selectionIndexes" 
                          options:NSKeyValueObservingOptionNew
                          context:nil];

到buildArrayController的最后。