Sharing a single NSDateFormatter instance

Formatting dates in cellForRowAtIndexPath or another method that gets called very often will make an app noticeably slower if an NSDateFormatter needs to be initialized on every call. Storing the NSDateFormatter in a property or making it static are both fine options but if it’s around anyway it might as well be used by the rest of the app. NSDateFormatter Instance Category //NSDateFormatter Category + (NSDateFormatter *)instance { static dispatch_once_t onceMark; static NSDateFormatter *formatter = nil; dispatch_once(&onceMark, ^{ formatter = [[NSDateFormatter alloc] init]; }); return formatter; } //Usage NSDateFormatter *dateformatter = [NSDateFormatter instance]; Drawbacks If there are multiple date formats in use the date format needs to be set before each use. Not a major drawback but it can get annoying. ...

August 15, 2013 · 1 min · Paul

Retina alterative to CGRectIntegral

CGRectIntegral is a function for rounding all the values of a CGRect at once, typically used for snapping frames to pixels. For a good example of how this helps prevent image blurring and other related rendering issues see this stackoverflow answer. On retina screens CGRectIntegral still rounds to the nearest point (1.0) rather than the nearest pixel (0.5) which isn’t ideal. My solution to this is implemented as a UIView category which matches my use case for CGRectIntegral 100% of the time. Your mileage may vary. ...

August 14, 2013 · 1 min · Paul

Checking if a UITableViewCell is fully visible

Sometime you need to know if a UITableViewCell is completely visible and for those times there’s this handy UITableViewCell category. //Place in UITableViewCell Category - (BOOL) isCompletelyVisible { // For parents category see pdenya.com/g/uiview_parents UITableView *tableview = (UITableView *)[self parents:[UITableView class]]; CGRect rect = [tableview rectForRowAtIndexPath:[tableview indexPathForCell:self]]; rect = [tableview convertRect:rect toView:tableview.superview]; BOOL completelyVisible = CGRectContainsRect(tableview.frame, rect); return completelyVisible; } I’d like to mention that you can skip this check entirely if your goal is to make sure a cell is completely visible. With UITableViewScrollPositionNone scrollToRowAtIndexPath:atScrollPosition:animated: doesn’t scroll at all if the cell is totally visible and in other cases it scrolls as little as possible which is usually the ideal behavior. ...

August 7, 2013 · 1 min · Paul

Tap anywhere else to cancel in Objective C

Whenever you have a modal element that outside touches should cancel a few things need to happen: Touches inside the modal element should behave normally Outside touches should not trigger touch events on tappable elements Outside touches should trigger a handler to close the modal In my case I was swiping a UITableViewCell and revealing a controls view that should close if any other UITableViewCell is tapped. hitTest:withEvent - The easiest method Touch events bubble down from the root view rather than up from the target view which makes this a bit easier. On whichever view needs to capture the touch events, we need to override hitTest:withEvent: to return nil and call a function whenever a modal is open and a view other than the modal is tapped. I overrode this method in my UITableView’s superview. ...

August 6, 2013 · 3 min · Paul

Custom Relative Time with Date Components

Here’s an if chain that figures out the relative time. The current version suites my needs but it’s easy to modify. //print date to countdown_label NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; NSDate *fromDate = [NSDate date]; NSDate *toDate = [user filtered_until]; NSDateComponents *components = [calendar components:NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:fromDate toDate:toDate options:0]; NSString *countdown_text = @""; if (components.day > 1) { countdown_text = [NSString stringWithFormat:@"%i days", components.day]; } //1d 4hrs else if (components.day > 0 && components.hour > 1) { countdown_text = [NSString stringWithFormat:@"%id %ihrs", components.day, components.hour]; } //1d 1hr else if (components.day > 0 && components.hour == 1) { countdown_text = [NSString stringWithFormat:@"%id %ihr", components.day, components.hour]; } //1 day ..this probably won't happen else if (components.day > 0 && components.hour == 0) { countdown_text = [NSString stringWithFormat:@"%i day", components.day]; } //12 hours else if (components.hour > 1) { countdown_text = [NSString stringWithFormat:@"%i hours", components.hour]; } //1 hour else if (components.hour == 1) { countdown_text = @"1 hour"; } //48 mins else if (components.minute > 1) { countdown_text = [NSString stringWithFormat:@"%i mins", components.minute]; } //1 min else if (components.minute == 1) { countdown_text = @"1 min"; } //0 min or less else { countdown_text = @"now"; }

July 30, 2013 · 1 min · Paul

Getting a particular superview in Objective-C

If you have, for example, a child view of a UITableViewCell and you need to get the UITableViewCell in question you can quickly do something like: UITableViewCell *cell = (UITableViewCell *)the_view.superview.superview; It works but this code is fragile because it requires that the view heirarchy not change (also things like this usually point to a code organization issue but hey, i’m not here to judge). If we want to be able to add a scrollview in between without editing this method we’ll have to take a different approach. ...

July 11, 2013 · 1 min · Paul