Crypto Tech in Zug

I attended a meetup in Zug tonight on using tokenization and distributed ledger technologies to help attain sustainable development goals.

This was the second meetup in a month on using crypto currency tech to effect positive change in the world. Very interesting stuff.

I love that there is a community here that is engaged in having these discussions. The technology is still in its infancy.

Clarification: I think sh*tcoin mining is the devil’s work, and I think there’s a huge crypto currency bubble waiting to burst.

But remember how it felt in 2008 when the App Store launched? Or in the late 90’s with the web? That’s crypto tech in Switzerland now.

Solo Stove Bonfire Mini-Review


Last weekend I impulse purchased a Solo Stove Bonfire fire pit because it looked awesome and was highly reviewed, we’ve wanted a fire pit or outdoor heater, there was a 10% discount for Earth Day weekend, and the mobile website accepted Apple Pay which made checkout super easy.

It arrived today and I was super eager to test it out. I had already purchased some 2″ paver stones to set it on (to protect our wood deck), firewood, and marshmallows.

What follows is my first impression mini-review after using it for the first time:

  • It lights quickly and easily. I used some straw, a few pieces, of kindling, and then straight to logs. There was no need for lighter fluid or fire starters or extra feeding of paper. I made a small bed of straw, put 6 pieces of kindling and 1 log on top and then lit it. Once the fire was going each additional log ignited quickly.
  • Once it heats up, it does produce less smoke than a normal campfire / fire pit. It takes a good 10-15 minutes to reach this point though.
  • The fire pit needs to be both pre-heated and full of logs in order to get the secondary combustion where pre-heated air flows into through holes around the upper rim to form flame jets that burn the smoke emitted from the main fire.
  • It seems to burn through wood pretty quickly.
  • Once the flames die down, it forms a great bed of embers for roasting marshmallows.
  • It burns the wood almost down to nothing. I had a few golf ball sized chunks of charcoal but mostly fine ash left over.
  • The fire pit cools down quickly. I was surprised how quickly it cools down. Because it burns so efficiently, I think it burns everything it can down to ash and then when there’s nothing left it quickly cools. I imagine the same airflow that allows it to burn so efficiently also contributes to the rapid cooling afterwards.
  • 👍

 

​Secondary combustion: ​Look for the jets of flame periodically forming around the rim


Perfect bed of embers for roasting marshmallows

Thoughts on iPhone 7 Plus

Four months ago I replaced my iPhone 6S with an iPhone SE. I loved the idea of the SE: the best features of the 6S with the form factor of the 5/5S for $250 less. Why did I switch? Well, there are a few things I’ve never liked about the 6-series phones compared to the 5-series:

  1. Slippery rounded sides
  2. Power button opposite the volume buttons. I find it very difficult to press the power button without also pressing volume up (and vice versa).
  3. Redesign of the volume buttons

Specifically with the iPhone 6S (especially after a year with the 6 Plus), I was disappointed with its anemic battery life. Not a deal breaker as I can charge at my desk and in my car, but not great either. I never really got into 3D Touch, so I didn’t miss not having it on the SE. The faster Touch ID on the 6S was actually an annoyance to me with iOS 9 and the difficult to press side-mounted power button.

So I was happy to give the SE a try. I enjoyed the fun pink (rose gold) color. The battery life was much better. Mostly I just appreciated the return to the easy-to-grip 5-series form factor. I’ve been very pleased with the SE.

I’m an iOS developer and I tend to focus on UI, so of course I was going to get a 7-series phone eventually. The questions were: (1) which model, and (2) would it replace my SE as my daily driver.

The dual lens camera system available only in the 7 Plus, pretty much decided both those questions. I waited until the SIM-free unlocked phones were available in the U.S. before placing an order, so I only received my 7 Plus this week.

Impressions So Far

  • The matte black color is gorgeous. I’d love to see this color on watches, iPads, and MacBooks.
  • I enjoy having a 5.5″ screen back after a year away.
  • I 💜 the new home button. It feels great.
  • The rounded sides are still slippery and the power button is still not easy to use
  • 2x camera mode is great. Zooming up to 10x is handy. I love the new zoom interface.
  • This is my first 128 GB phone. I could get used to this! 32 GB is now out of the question for me if I am to use the device for more than just testing.
  • 👍

Why so serious?

This morning at breakfast my wife and I were casually discussing the hypothetical question: “What possession of your partner’s would you like to throw away?”. Typically the answer might be that beat-up recliner left over from college days or an old, ratty (but much beloved) t-shirt. Our 7 year-old son, though interpreted the question differently and asked, “Mommy, wouldn’t you like to get rid of Daddy’s seriousness?”

That really took me aback. What, me serious? Why just last night while my wife was working late in the office, my son and I had a video game and ice-cream party at home. We even made an ice-cream run so that we could have seconds, and we went crazy with the sprinkles and toppings. How could he say I was serious, while my wife was the fun one?

A bit of background: my wife and I both work and we both take our work very seriously. While we may not be workaholics, we probably come close, and at a minimum we are both quite passionate about what we do. If anything, I think my wife is more serious at work than I am. Not that she’s mean or anything, far from it, it’s just that she expects the same competency and diligence from her colleagues that she demands from herself, and has little patience for ineptitude or lack of effort. The main difference I think is that while my wife works in an office, I have been working from home for the past 12 years.

I love working from home, and it would take a lot to convince me to return to an office full-time. I have worked from home for our son’s entire life, so for him that’s how the world works: mommy works in an office, and daddy works at home. But a downside that I hadn’t really considered before today is that this means that our son is exposed to my business side on an almost daily basis. I think many people who don’t work at home, imagine that the biggest challenge to working at home would be to remain focused and continue to work instead of spending all day goofing off. Perhaps that’s the case for most people. For me though, the problem is exactly the opposite: learning to leave work behind and have more life in my work-life balance.

My work-life balance issues have been compounded by the fact that for the past 2.5 years or so, I’ve been working harder than ever. I decided at the beginning of 2012 that I really wanted to get better at being an iOS developer, and began taking extra steps to achieve that goal. That meant that on top of my full-time development job I would write blog posts, work on open-source projects, read technical books and blogs, watch technical videos, work on the occasional consulting project, and work on conference presentations (create the talk, make slides, write sample code, and practice the talk). All of the above has already paid off for me: I feel I’ve improved at a much faster rate over the past 2 years than over the previous decade. It has brought me 2 jobs that have each improved my work satisfaction and additional consulting work which has done the same. But the cost has been many weeks of early mornings, late nights, and weekends spent coding instead of enjoying my family.

One of the things I love most about working from home is the flexibility it brings. Being there (almost) every day when my son arrives home from school is priceless. It’s the perfect time to take a break, head downstairs, get a hug and ask him how his day at school was. But somedays if I happen to be in the middle of a conference call or am deeply focused on a difficult task with a critical deadline looming, I can’t take that break, and if my son comes up to tell or ask me something, he glimpses my serious, focused side, and depending on what’s going on (e.g. conference call with a client) I may hardly be able to acknowledge his presence let alone have the conversation he wishes to have with me.

Why so serious?

This morning was definitely a wakeup call for me. I’m sure I’ll never be able to “throw away my seriousness”, but I can make an effort to not think about work outside of work hours, and to take every opportunity to appreciate and enjoy my wife and our son. After all, if I can’t take advantage of the flexibility that working at home affords me, then what’s the point? Kids grow up so fast that I need to savor every precious moment.

Speaking of which, it’s Memorial Day weekend and our pool has just opened for the season. It’s high time to close my laptop and go have some fun.

 

 

Device orientation vs interface orientation

Just today I got bit by confusing device orientation and interface orientation. I really should know better. Device orientation is of course the orientation that the device is currently being held in, while interface orientation is the orientation of the running app’s user interface.

What I was trying to do was to hide the status bar while in landscape mode and show it in portrait mode for an iPhone app that operates in the 3 principal orientations: portrait, landscape left, and landscape right.

To achieve that I was using code like this:

#pragma mark - Status Bar

- (BOOL)prefersStatusBarHidden
{
    return (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]));
}

#pragma mark - Orientation

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    
    [self setNeedsStatusBarAppearanceUpdate];
}

This works fine at first blush, especially in the simulator, but not so well in practice. First off, the app doesn’t even support all 4 possible interface orientations (the fourth being upside down portrait), so what happens when the phone is held upside down? Well the interface orientation doesn’t change from its previous orientation (most likely landscape) but the device orientation is not landscape and so the status bar appears. Bug.

But even worse, there are additional device orientations (namely face up and face down) that are neither portrait nor landscape and have no matching interface orientation. If the phone was last in landscape interface orientation and then gets laid flat on the desktop, the device orientation is no longer landscape (it is flat), and so the status bar appears. Bug again.

Just for the record, here’s the definition of UIDeviceOrientation:

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
};

And here’s the definition for UIInterfaceOrientation:

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
};

It’s interesting that UIInterfaceOrientation is defined in terms of UIDeviceOrientation.

TL;DR;

So what I should have been doing was this:

#pragma mark - Status Bar

- (BOOL)prefersStatusBarHidden
{
    return (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]));
}

This works as expected when the device is upside down or flat.

Standing Desk 1.0

Standing positionEarly this year I purchased my first standing desk. Originally I was looking at treadmill desks as a way to help get in shape despite the long hours I spend at my desk each day. I didn’t feel like I had the time for a DIY project, so I was considering pre-built solutions such as this LifeSpan Fitness treadmill desk. Their desk seemed nice, but I had 2 problems with it. First it is fixed in height and so could never be used as a sitting desk, and second I already have 3 desks in my office that I like and the last thing I needed was a 4th desk.

The other reason I was looking at treadmill desks was because sitting at my desk was becoming increasingly more uncomfortable. I’ve been programming professionally for 15 years and sitting long hours each day the entire time. Up until last year, I would only get sore after more than 10 or 12 hours of sitting. But this past year that dropped to 8 and then 6 and then 4 hours or even less. Changing positions and getting up for stretching breaks (which I do regularly) wasn’t helping much. Sitting at my desk had literally become (forgive the pun) a pain in the ass. Of course to address this problem I didn’t need a treadmill, just a standing desk. But I figured that standing all day would quickly become just as painful as sitting all day, so what I really needed was an adjustable desk. (LifeSpan and other companies also sell standing desk treadmills without the desk, so I could always add a treadmill later.)

So after some research I decided to get a GeekDesk without a top and reuse the existing glass top from one of my desks, and just swap out the existing frame for the GeekDesk one. I chose the more expensive Max version mainly for the programmable presets, and I chose a small frame to fit one of my two 120 cm desks (I could have gotten a large frame for my 160 cm desk).  Using my own top saved me $264 between reduced price and reduced shipping.

GeekDesk Max frameCustomer service at GeekDesk was great and my desk arrived promptly. You assemble it yourself, but that’s easy and the build quality is great.  Adding your own glass top is probably even easier than adding your own wood top because you can assemble the desk upright and merely set the glass top in place. The one thing you need are little rubber / silicone pads to put in between the metal frame and the glass top. These cushion the top but also provide the necessary friction so that the top will not slide sideways with pressure. Fortunately I already had these from my previous desk frame.

When the desk is in seated position the before (above) and after (below) appearance is practically unchanged.

Before
After

In Use

At first, I was changing positions every 30 minutes using a timer to remind me. I rotated between 3 positions: sitting in a chair, standing, and sitting on a balance ball (with the desk in its lowest position). Changing so frequently was no doubt overkill and most of the time I had trouble focusing properly while standing. Working while sitting is a hard habit to break. 9 months later I still sit most of the day, but once or twice a day I will move the desk  into standing position and stand for a while. I probably ought to change more often. I still find it hard to concentrate while standing, so whenever I’m faced with a particularly difficult problem to solve, I always have an urge to sit. Overall I’m very happy with the purchase and glad I have the option to shift my work position upon demand. Maybe next year will be the year I am able to add a treadmill into the mix.

Lowest position

CocoaConf San Jose wrap-up

This past weekend I had the pleasure of attending and speaking at CocoaConf San Jose. This was the 6th CocoaConf event I’ve attended, and I believe it was one of the best. Highlights for me included:

  • Matt Drance‘s opening keynote where he discussed the importance of people in our work: our customers (users), our co-workers, and ourselves. This is something that we as engineers can often lose sight of.
  • Jaimee Newberry‘s session on brainstorming. Jaimee is a fantastic speaker and always fun to watch, and there was plenty of info on how to manage and get the most out of brainstorming sessions, which I’d like to try on my next project.
  • Ben Lachman‘s session on prototyping, which covered a variety of tools and workflows and included a demo of the yet to be released Briefs 2 (which I plan on buying as soon as it is available. Seriously, just take my money already!).
  • Marcus Zarra‘s session on the MVC-N design pattern, which contained a strong admonition against relying on 3rd party code (especially networking code). This is going to change how I approach the next client project I manage. This talk alone made attending the conference worthwhile.
  • Daniel Pasco‘s session on the long road and various pitfalls encountered in transforming his company, Black Pixel, from a client-work company into a product company (Black Pixel makes the excellent Kaleidoscope 2 — you should buy it). Valuable lessons for anyone seeking to go indie.

I presented 2 talks of my own. Thursday evening I delivered a talk on UICollectionView. This was the 4th (and probably final) time I delivered this talk over the past 6 months. The sample app (which contains 5 different layouts and multiple examples of advanced customizations) is available on GitHub here, while the slides can be downloaded here.

photo pinch

Saturday morning I presented “Animation: From 0 to Awesome in 90 Minutes”, which is an animation talk that begins with some design principles of animation (drawn from Phil Letourneau’s portion of our joint animation session at Renaissance), proceeds to discuss UIKit and Core Animation (and the limitations of UIKit), then takes a close-up look at flipping and folding animations, and wraps up with some general graphical performance tips. This talk is sort of an evolution of both the Renaissance talk and my Enter The Matrix: Reloaded sessions from 2012, and yet is also its own thing. I debuted it last month at CocoaConf DC and this was its second iteration. The sample app is available on GitHub here, while the slides are available for download here. My favorite portion of the app is the touch-enabled timing curve widget that lets you create custom cubic bezier curves by dragging 2 control points (and shows you their values). I think that was also one of the big takeaways from the talk: that you can have an animation overshoot its endpoint and then snap back by simply applying the right timing curve to a basic animation with no need for multiple or keyframe animations.

Timing curve

This wraps up the CocoaConf Spring Tour and my own 3 conference “Spring Tour” as well. I plan to take the summer off from speaking and pick it up again in the Fall.

Speaker kit

Gear
I thought I might list the gear I pack when presenting at conferences

  • 15″ retina MacBook Pro — my favorite Mac ever. Great for presenting, coding, and preparing slide decks
  • iPhone 5 (AT&T) — my constant companion. Tethering via Personal Hotspot usually beats hotel / conference WiFi every time. Also, I often run Presentation Clock on it while I’m speaking to help me budget my time (propped up by a Glif).
  • iPad mini with Verizon LTE — often my demo device. The non-retina screen actually makes for a better presentation device. Also an alternate tethering source for internet. Having both AT&T and Verizon as data options helps cover all the bases. Recently I’ve had luck running demos on the iPad mini while displaying via AirPlay and Reflector.app back onto my MacBook all driven by the iPad’s Personal Hotspot. This lets me avoid Xcode and the iOS Simulator during presentations.
  • Kensington wireless presenter (with extra lithium batteries) — rock solid and works great and means I’m not tied to my laptop or the podium.
  • 3 x 4 GB USB thumb drives — for distributing slides and sample code at the beginning of the talk (have I mentioned that conference WiFi is usually terrible?)
  • Mophie juice pack with charging cable — I could probably leave this at home, but it’s nice to have a backup and offering power is a great way to meet people.
  • 2 Lightning to USB cables — for charging phone and iPad simultaneously. Or for debugging (perhaps running Instruments on) an iOS device during a demo.
  • 2 x 12W USB Power Adapter — why would I cart these larger iPad chargers around when traveling? Well I figure you often only get a limited amount of time with an outlet, so you need to make that time count. For that reason I actually upgraded to the 12W adapters (the ones that come with the iPad 4) from the 10W adapters that accompanied the first 3 iPads, merely for the modest gain in charging time. Having 2 means I can charge the iPad and iPhone simultaneously or else the iPad and the Mophie (typically what I do overnight)
  • 1 x 5W USB Power Adaptor — so why bring this one at all? Well, I hate having to remember to swap devices between a limited number of chargers. This allows me to charge my iPhone plus the iPad and the Mophie overnight, so they all start each day fully charged.
  • 4 outlet portable power strip — great for many hotel rooms that often offer only a single outlet in any one place. This lets me plug in all 3 chargers plus charge my MacBook.
  • Lightning to VGA Adapter — in case I need to do VGA out directly from my iPhone or iPad. This is strictly a contingency plan. But also nice that you can do so while debugging or running Instruments via the integrated Lightning port (this used to be a feature limited to the HDMI adapter).
  • mini-displayPort to VGA adapter — for connecting my MacBook to the projector. Typically the conference always provides these but you should always carry your own.
  • MagSafe to MagSafe 2 Converter — in case the power adapter at the podium / presenter’s table is the original MagSafe. Lately though, conferences have been supplying both flavors!
  • Thunderbolt to Ethernet adapter — this is really more of a WWDC thing, but you never know when you’ll need access to ethernet.
  • Lightning to 30-pin Adapter — I’m only carrying Lightning devices and cables, but this is just in case I need to charge from a 30-pin cable (perhaps when riding in a car; I haven’t upgraded my car chargers to Lightning since my wife is still on an iPhone 4S)

So that’s what I’m currently carrying to conferences. I enjoy the convenience of leaving my full-sized iPads at home and only having to bring Lightning-flavor accessories. What are you carrying to conferences?

A potential pitfall of CGRectIntegral

This morning while I was checking an app for misaligned elements, I happened upon a misaligned button. (If you’re not using either the iOS Simulator or Instruments to check your app for misaligned images, you should be, but that’s a post for another day.)

Checking the code it was obvious to me where the problem was.

backButton.frame = CGRectMake(5, (navigationBar.bounds.size.height
    - imageBack.size.height)/2, imageBack.size.width,
    imageBack.size.height);

Centering code is especially prone to pixel misalignment. In this case imageBack has a size of (50, 29) while the navigationBar has a height of 44 points. The code above generates a rect with origin = (5, 7.5) and size = (50, 29). So the image ends up vertically misaligned, which in turn makes the child text label inside also misaligned, and hence they show up painted in magenta when the Color Misaligned Images option is checked in the iOS Simulator Debug menu.

This looks like a job for CGRectIntegral, right? But when I change the code to this:

backButton.frame  = CGRectIntegral(CGRectMake(5, 
    (navigationBar.bounds.size.height - imageBack.size.height)/2,
    imageBack.size.width, imageBack.size.height));

I end up with this:

The button is no longer misaligned, but it is now being stretched (hence the yellow wash). Debugging shows that CGRectIntegral has converted the input rect of (5, 7.5) x (50, 29) into (5, 7) x (50, 30). So now the image is being stretched vertically by 1 point. That might be fine for UILabel but not for an image.

The other issue with using CGRectIntegral is that the original rect is actually fine for retina devices because they have 2 pixels per point, so a value of 7.5 actually falls on a pixel boundary, and is the optimal centering for this image. If we adjusted it to origin.y = 7 (without stretching) then it would be 2 pixels closer to the top than to the bottom on a retina device.

I’ve written some helper functions to correctly pixel align rectangles (not point align) for both retina and non-retina screens, and posted them in this gist.

Under non-retina it would convert the rectangle to (5, 7) x (50,29) to pixel align it without stretching, while under retina it would leave the rectangle unmodified at (5, 7.5) x (50, 29).

This finally clears the magenta (alignment) and yellow (stretch) washes from the button:

Addendum

According to the Apple Documentation for CGRectIntegral:

A rectangle with the smallest integer values for its origin and size that contains the source rectangle. That is, given a rectangle with fractional origin or size values, CGRectIntegral rounds the rectangle’s origin downward and its size upward to the nearest whole integers, such that the result contains the original rectangle.

The fractional origin of (5, 7.5) is rounded downward to (5, 7), but I initially thought the size would be left unmodified (not rounded up) because it already comprises 2 whole integers. But that wouldn’t contain the original rectangle, whose lower right corner is positioned at (55, 36.5). In order to contain the original rectangle, the height has to be increased by 1 point from 29 to 30.

How to Add a Decoration View to a UICollectionView

Decoration views are one of the great new features of collection views.  Unlike cells and supplementary views (e.g. headers and footers), decoration views are layout-driven rather than data-driven.  You can think of them as the shelves in the iBooks Store interface.  Background views are another good candidate for implementing as decoration views.

So how exactly do you add decoration views to your collection view?  It’s actually pretty simple.

  1. Create your decoration view.  It should be a subclass of UICollectionReusableView.
  2. Create your own UICollectionViewLayout subclass if you don’t already have one.  This can be a subclass of UICollectionViewFlowLayout if that’s what you’re using.
  3. Register your decoration view with your layout either by class name or nib.
  4. Return the appropriate attributes for your decoration view in layoutAttributesForElementsInRect:
  5. Implement layoutAttributesForDecorationViewOfKind:atIndexPath: to return attributes for the specified decoration view.


In my sample project IntroducingCollectionViews, the first layout, GridLayout, is an iBooks Store-style layout derived from UICollectionViewFlowLayout.  The layout has shelves underneath each row of cells that are implemented as decoration views.  I will go through the steps above to show how I implemented the shelf views in the GridLayout class.

Create the decoration view

I created a ShelfView class derived from UICollectionReusableView.  It’s a very simple view (no subviews) — I just set backgroundColor to a color from a pattern image and add a drop shadow.  (Performance tip: I set the shadowPath for the drop shadow on the backing layer.  See here for why that’s important.)

Subclass UICollectionViewLayout

I created GridLayout as a subclass of UICollectionViewFlowLayout.  The superclass handles the heavy lifting of positioning all the cells and headers and footers, but I have to handle the decoration views.

Register the decoration view

In the init method for GridLayout I register the shelf view by class.

[self registerClass:[ShelfView class] forDecorationViewOfKind:
    [ShelfView kind]]

(Where kind is a convenience class method I added to return the kind string. Kind becomes important when you have multiple decoration view classes in your collection view.)

Implement layoutAttributesForElementsInRect:

This method is the meat of a layout.  It’s where the layout tells the collection view about all items (cells, supplementary views, and decoration views) that are to appear within a given rect (generally the current visible rect based on the collection view’s current contentOffset).  The collection view in turn takes over instantiating (or reusing) all necessary views and setting their position, size, and other visible characteristics (alpha, transform, zIndex, etc.).

Because I’m deriving from UICollectionViewFlowLayout, I can just call super to get the attributes for all the cells and supplementary views.  I just need to add the decoration views (if any) to that array.  But in order to know which decoration views might fall within a given rect, I need to do some calculations ahead of time.  To do that I need to override prepareLayout.  This is the method that gets called every time the layout becomes invalidated and is where you can calculate where all the collection elements should go.

In prepareLayout I calculate where the shelves will go (don’t forget to call super).  Unfortunately, this means replicating much of the flow layout positioning since I want to position each shelf directly under each row (line) of speakers (actually each shelf goes under the speaker name label of each SpeakerCell).  I calculate the frame of every shelf rect in the entire content area and store them in a dictionary keyed on index path where section is of course the section the shelf resides in and row is the 0-based index of the shelf within each section moving top to bottom. (This will be important when it’s time to implement layoutAttributesForDecorationViewOfKind:atIndexPath:)

Meanwhile, back in layoutAttributesForElementsInRect: I of course call super and then I enumerate through all my shelf rects and for any shelf rect that intersects with the specified rect (meaning a decoration view should appear at that position), I create a set of layout attributes for that decoration view and add it to the array of attributes returned by super.  To create the attributes I call

[UICollectionViewLayoutAttributes 
     layoutAttributesForDecorationViewOfKind:[ShelfView kind] 
                               withIndexPath:key]

Where I just pass in the kind and the index path (which happens to be the key of the dictionary I’m enumerating through).  Then I set the frame to be the rect I have stored and also set zIndex to 0 (I set zIndex to be 1 on all the cells and supplementary views to make sure they appear in front of the shelves).

Implement layoutAttributesForDecorationViewOfKind:atIndexPath:

This one is pretty easy.  Because I stored my shelf rects in a dictionary keyed on index path, I just use the passed index path to fetch the shelf rect and then I just create the attributes exactly as I did for layoutAttributesForElementsInRect:  (Actually I have yet to see this particular method ever get called.  I have a breakpoint set on it and have never had it be triggered.)

Summary

And that’s what it takes to add decoration views to a collection view.  Decoration views are a cool new feature of collection views and are just one of the improvements of UICollectionView over its predecessor for data display on iOS, UITableView.

Once again, the sample project is on GitHub here. The wood paneling backgrounds are part of a set of retina-ready repeatable assets by Glyphish.

Go forth and make amazing collection view layouts!