【问题标题】:objective-c building my own custom calendar (nsarraycontroller observer problems)Objective-c 构建我自己的自定义日历(nsarraycontroller 观察者问题)
【发布时间】:2011-02-05 10:04:57
【问题描述】:

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

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

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

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

我在我的 NSArrayController 中添加了一个观察者,以了解用户何时单击日期,这允许我向我的父类发送一条消息,告诉它更新我在 cal 下的表列表。

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

// 观察我们的数组 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(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,我正在谈论灰色的日期)然后观察者被调用两次,因此我的数组被送回 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有道理吗?我可以暂时禁用集合视图上的点击事件吗?

更新2 好的,我尝试添加这个

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

                    [self.collectionView setSelectable:NO];

                    [self buildArrayController];

                    [self.collectionView setSelectable:YES];

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

【问题讨论】:

    标签: objective-c cocoa


    【解决方案1】:

    看起来你的观察者会被调用两次:

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

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

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

    到 buildArrayController 的最后。

    【讨论】:

      猜你喜欢
      • 2012-08-19
      • 2011-03-27
      • 1970-01-01
      • 1970-01-01
      • 2011-12-14
      • 1970-01-01
      • 2014-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多