cocoa - objective-c building my own custom calendar (nsarraycontroller observer problems) -
i have time being building own calendar because standard mac cal sucks in terms of layout.
what have done make nscollectionview holds dates, , in code add each date array controller.
so far works fine , cal showing!
take @ ss here: http://cl.ly/0z3a2i12242b2d1m3z1n
i have added observer nsarraycontroller know whenever user clicks date, allows me send message parent class telling update table-list under cal.
my observer looks this:
// observing our array - (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]; } } } } }
}
my big problem when user presses date before current month (look @ ss, iam talking grayed-out dates) observer gets called twice , therefor array sent 2 months, iam not sure how counterfight , have been struggling days..
my code building array controller looks this:
- (void) buildarraycontroller { nslog(@"building array controller"); // remove observer, objects , set selection -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 current month have nsrange daysinmonth = [self daysinmonth:self.currentmonth]; // save current month int later int month = [nowcomps month]; // getting days add before month nsdatecomponents *weekdaycomponents = [self.currentcal components:nsweekdaycalendarunit fromdate:self.currentmonth]; int weekdaystoadd = (([weekdaycomponents weekday] == 1) ? 8 : [weekdaycomponents weekday])-2; // add days befroe current month, ie when 1st day of month on wednesday f.ex. nsdate* lastmonth = [self movemonth:-1]; nsrange daysinlastmonth = [self daysinmonth:lastmonth]; nsdatecomponents *lastmonthcomps = [self.currentcal components:(nsyearcalendarunit|nsmonthcalendarunit|nsdaycalendarunit|nsweekdaycalendarunit) fromdate:lastmonth]; (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 month dates (int = 1; < 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 current month nsdate* nextmonthobj = [self movemonth:1]; nsdatecomponents *nextmonthcomps = [self.currentcal components:(nsyearcalendarunit|nsmonthcalendarunit|nsdaycalendarunit|nsweekdaycalendarunit) fromdate:nextmonthobj]; (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 our array controller [self.arraycontroller addobserver:self forkeypath:@"selectionindexes" options:nskeyvalueobservingoptionnew context:nil]; // figure out object should 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]; } }
thats it! suggestions?
(btw, if have heads on making code better please tell me, first project in objective-c ever :))
update 'feel' not observer problem somehow, when press before date in cal , method rebuilds array somehows re-send/click on next view when items updated, htis make senes? temporary disable click events on collection view?
update2 okay, tried adding this
self.selecteddate = obj.dateobj; self.currentmonth = [self movemonth:(nsinteger)-1]; [self.collectionview setselectable:no]; [self buildarraycontroller]; [self.collectionview setselectable:yes];
removing selectiable collecitonview not work, must observer shomehow gets called twice.. :t
it looks observer called twice:
- the user selects new date, before current month. causes change in "selectionindexes" , causes observer method called.
- in buildarraycontroller, remove observer, make changes reactivate observer. after re-adding observer, call 'setselectionindex' on array controller, causes second observation callback.
on second callback, obj.isold false, luckily don't enter infinite loop of this. try moving call to
[self.arraycontroller addobserver:self forkeypath:@"selectionindexes" options:nskeyvalueobservingoptionnew context:nil];
to end of buildarraycontroller.
Comments
Post a Comment