2

I'm the author of a calendar library for iOS, and I'm thinking about how I can improve it, because it's become obvious that people aren't understanding it.

Right now, I have a datasource protocol that consists of just one method, and it returns the events to show on a given date:

- (NSArray *)calendarView:(CKCalendarView *)calendarView eventsForDate:(NSDate *)date;

But, I've found that in the two years of the library being available, most of the feedback I've gotten has been, "how do I make events appear on the calendar?"

I always thought it was pretty intuitive:

  1. Create some events. The framework has an "event" object to work with.
  2. Keep your events sorted by date in some data source, like a dictionary, or Core Data.
  3. Return the appropriate event objects in the datasource.

What else can I do to make it clearer to other developers how I intended this to work?

Moshe
  • 57,511
  • 78
  • 272
  • 425
  • May be adding FAQ to your documentation with this kind of questions would help? – interrupt Oct 05 '14 at 04:20
  • 1
    The documentation is pretty thorough as it is, but I'm open to improving it. – Moshe Oct 05 '14 at 04:25
  • I think your documentation is pretty clear. Anyone familiar with, say, UITableViewDatasource would get the idea straight-away. Perhaps because your library also defines the Event class users are expecting the calendar view itself to provide the data model and they then add events by calling a method such as `addEvent`. Perhaps you could create a data source class that could be used "as is" to implement a data model if the user didn't want to make their own – Paulw11 Oct 05 '14 at 05:52
  • 2
    Provide a snippet instead of formal selector description under "Showing events" sections of your docs. Today's programmers hate reading docs, they love snippets and can build a solid product provided that there is enough snippets. – user3125367 Oct 05 '14 at 07:36
  • What about introducing a protocol that had a method that returned a date object instead of or in addition to the delegate method? – Moshe Oct 05 '14 at 09:51
  • 1
    FYI, this is the sort of question for which http://codereview.stackexchange.com is well suited. – Rob Nov 11 '14 at 14:28

3 Answers3

6
  1. Your user wants code she can copy and paste and then edit to fit her problem. She doesn't want to read about an interface and then implement it from scratch. So put a toy implementation of CKCalendarViewDataSource in your documentation. The toy implementation needs to work out of the box. Your user should be able to paste it into her project, compile, and see events in the calendar view. The toy can just use a hardcoded array of events (with calls to [NSDate now] as needed to ensure the default calendar month shows events).

    I think provide a working sample implementation in the README will do the most to alleviate your support headaches.

  2. Your user doesn't want to implement callbacks. She doesn't think in terms of waiting to answer a question; she thinks in terms of telling your library what to do.

    Add an events property to the view that is an array of CKCalendarEvent. Let the user set either the events or the dataSource. Note in the documentation and header comments that you recommend using the dataSource if there are more than a few dozen events. Raise an exception if the user sets both.

  3. If you keep getting asked “How do I make events appear on the calendar?” then put that language in your documentation. It's okay to be redundant in your documentation! Documentation is for humans, and humans need redundancy.

    You can have big section headers that say “How to Add Events to the Calendar”, and “How to Show an Event on the Calendar”, and “How to Make an Event Appear on the Calendar”, and they can all say the same thing (ideally with sample code) or just link to the “Showing Events” section.

  4. Explain in your documentation, near the top, that CKCalendarView needs a data source just like UITableView. Be explicit! You and I recognize the pattern, but apparently your users don't.

  5. Provide a better data source interface. Looking up events by NSDate isn't really ideal, because an NSDate specifies an instant in time, not a whole day. You want events that fall on a given calendar day, but you don't care about the time of day of the event. Are you passing midnight of the day of interest? What if the event is at 8 AM? Worse, what if the event is the next day at 12:01 AM, and daylight saving time starts on the day of interest? Not all days are 86,400 seconds long! Don't make your user muck around with NSCalendar; do it for her.

    I would prefer a message like this:

    - (NSArray *)calendarView:(CKCalendarView *)calendarView
        eventsOnOrAfterDate:(NSDate *)startingDate
        beforeDate:(NSDate *)endingDate;
    

    Pass midnight (or 1 AM on certain days in certain time zones) of the date of interest for startingDate. Pass midnight of the following day for endingDate. Note that you should allow the user to specify your calendar's time zone for computing these NSDates (but default to [NSTimeZone systemTimeZone]).

    It might be nice to specify the following message also, in case your user stores her events by calendar day and not with precise timestamps:

    - (NSArray *)calendarView:(CKCalendarView *)calendarView
        eventsForYear:(int)year month:(int)month day:(int)day;
    
Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks for all of this. There were several issues opened that complained that events weren't appearing on the calendar, and date comparisons was the culprit. Your final point really resonates with me and I'm going to think it through when doing a major update. – Moshe Nov 30 '14 at 01:39
0

I would go for a CKCalendarEvent protocol:

@protocol CKCalendarEvent <NSObject>

- (NSDate *)date;
- (NSString *)title;
- (NSDictionary *)info;
- (UIColor *)color;

@end

so users can provide events in an array directly using a events property:

calendar.events = @[ event1, event2, ... ];
HiDeoo
  • 10,353
  • 8
  • 47
  • 47
0

Perhaps it would be good idea to change the construction logic of your CKCalendarView

Example:

CKCalendarView *calendar = [[CKCalendarView alloc] initWithDataSource:self];

or

CKCalendarView *calendar = [[CKCalendarView alloc] initWithEventLoader:self];
alex
  • 8,904
  • 6
  • 49
  • 75