title: objective-c building my own custom calendar (nsarraycontroller observer problems)
body: <p>I have for some time now being building my own calendar because the standard mac cal sucks in terms of layout.</p>
  
  <p>What i have done is to make an NSCollectionView that holds all my dates, and then in my code i add each date to an array controller.</p>
  
  <p>So far all works fine and the cal is showing!</p>
  
  <p>Take a look at my ss here: <a href="http://cl.ly/0Z3a2i12242b2d1m3Z1n" rel="nofollow">http://cl.ly/0Z3a2i12242b2d1m3Z1n</a></p>
  
  <p>I have added an observer to my NSArrayController to know whenever a user clicks a date, this allows me to send a message to my parent class telling it to update my table-list under the cal.</p>
  
  <p>My observer looks like this:</p>
  
  <p>// observing our array
  - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {</p>
  
  <pre><code>if([keyPath isEqualTo:@"selectionIndexes"])
  {
      if([[self.arrayController selectedObjects] count] &gt; 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];
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>}</p>
  
  <p>My big problem is that when the user presses a date before this current month (look at the SS, iam talking about the grayed-out dates) then the observer gets called twice and my therefor my array is sent back 2 months, iam not sure how to counterfight this and now i have been struggling for days.. </p>
  
  <p>My code for building the array controller looks like this:</p>
  
  <pre><code>- (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 &lt; 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 &lt; 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 &lt; 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];
      }   
  }
  </code></pre>
  
  <p>Thats it! Any suggestions?</p>
  
  <p>(btw, if you have any heads up on making my code better please tell me, this is my first project in objective-c ever :))</p>
  
  <p><strong>Update</strong>
  I 'feel' its not really the observer that is the problem but somehow, when i press the before date in the cal and my method rebuilds the array it somehows re-send/click on the next view when the items are updated, does htis make senes? Could i temporary disable click events on the collection view?</p>
  
  <p><strong>update2</strong>
  Okay, i tried adding this</p>
  
  <pre><code>                    self.selectedDate = obj.dateobj;
                      self.currentMonth = [self moveMonth:(NSInteger)-1];
  
                      [self.collectionView setSelectable:NO];
  
                      [self buildArrayController];
  
                      [self.collectionView setSelectable:YES];
  </code></pre>
  
  <p>removing selectiable for the collecitonview but it does not work, so it must be the observer that shomehow gets called twice.. :t</p>