Repartee

icon1024Spaceman Labs was founded on one principle: that we are two extremely debonair individuals capable of making extremely excellent iOS apps. Today we advance this hypothesis by introducing our flagship app, Repartee. In truth, Repartee is the app we created this company to build. We brought our iOS expertise and keen design sense to bear, and added new competencies all over the place—particularly in creating a server application to complement the iOS client.

But I’m getting ahead of myself.

What is Repartee?

Repartee is the best way to plan your parties, participate in your friends’ events, and appreciate the memories afterwards. It has a slew of features, a selection of beautiful stationeries, and some really cool technology under the hood. Best of all, it’s completely mobile. Creation, hosting, attendance, sharing—it all takes place on your iPhone. (There’s a thin web client for guests who don’t have iPhones, of course.) Oh, and because we’re a startup with more dreams than business sense, it’s completely free.

Get it get it!

Sounds great, right? Before you read any further, go download Repartee here. Give it a try, then let us know what you think. If what you think is positive, do it in the form of an App Store review. It’s amazing what a big difference that makes, so please, if this blog has ever been helpful to you, consider leaving a review to be paying back the favor.

Features

Because this is primarily a development blog, I’ll talk a little bit here about some of the cool things we have going on that aren’t immediately apparent to the end user.

Creation

  • Every event needs a location. We use Foursquare’s excellent API to auto-complete venues when possible. If you’re having your birthday party at the W Hotel, you shouldn’t have to type more than a few characters.
  • We want to encourage our users to try out different stationeries to find the best one for their event. To that end, all the details you enter into a stationery template are saved. They’ll be applied to each new one you try out.
  • Repartee is time zone-aware. If you plan an event in a different time zone, it will ask to make sure your start and end times are in the venue’s time zone, and adjust them if needed.

Inviting

  • Repartee invites your friends no matter what contact information you have for them. Email, text message, or Facebook—the experience for the user is the same. We handle the work differently on the backend, which no one needs to care about.
  • When you select a contact, Repartee checks a secure hash of their contact information to see if they’re already on the platform. If so, they’ll receive a push notification, and we can additionally contact them through whatever means they prefer.

RSVPs

  • Our emails have links to open on the website or in the app, if it’s installed. If you visit the site on a desktop, we provide a simple means to transfer the event information to the app on your phone, even if you’re not signed in with the same contact information the host invited. There’s a really neat flow on the app for this—check out the “Find an Event” button.
  • RSVPs include notes for the host (e.g., “I’ll be a little late but I’m looking forward to it!”), and can be changed at any time as circumstances require.
  • The list of invites color-codes guests by RSVP status. The host can mark individuals as VIP by tapping on their photos.

Attendance

  • When VIPs arrive, the host will receive a push notification.
  • If guests take photos at the event—same time and place—they’ll be allowed to turn on auto-uploading for a huge ease-of-use boost. They do get to review which existing photos will go up when they turn it on, and can deselect embarrassing ones.
  • Repartee tries to keep guests engaged in both the event itself, and the second-screen-esque experience taking place in Repartee, through the judicious use of push notifications. This stops when they leave the event.

Photos

  • The photostream is optimized for exploration. More interesting photos are bigger, to invite interaction.
  • Photos can take some time to pull down on a slow network, so the data model includes a size and average color. Repartee will show a color block of the right dimensions, and seamlessly fade in the photo when it’s downloaded.

Dashboard

  • One of our core competencies from our Roambi days is charting, which means we know exactly how much work it is to build a flexible, durable charting library. That’s why we opted to use third-party charts.
  • We considered the balance of information versus privacy very carefully. The host gets to see a lot of data in the dashboard, but anything potentially embarrassing is anonymized. The aggregate charts are the fun part, anyway.

I hope you’ve enjoyed this brief tour of some of Repartee’s hidden technical gems. There’s a lot more in there, and we’re continuing development at a rapid clip. Stay tuned here for bits we’ll open-source, lessons learned, and so on, as we have the chance. Even better though, keep an eye on the release notes as we push out new versions. And don’t forget to leave a review!

Posted in Software | Tagged , , | Leave a comment

Blocks: A Retain Ménage à Trois

This is a topic that I have considered writing about for some time now; in fact, I have a draft post from 2011, right after I finally decided to start using blocks. That post touched on a few areas of nuance in block memory management, but it basically all boiled down to: Memory Management and Blocks Can Be Tricky. I thought most of its talking points were tired, old news at this point — it seems I was wrong.

Last night I saw a flurry of tweets linking to a blog post about NSNotificationCenter’s block based API being ‘harmful’. I use this API fairly heavily, and was interested to see what kind of trouble I was in for. Drew Crawford does a great job of providing a narrative very similar to my first WTF moments from the early days of familiarizing myself with blocks. That said, I feel like the article’s title would be more accurate as: NSNotificationCenter with blocks considered harmful, unless you understand how self is captured.

Drew did a great job of putting together a simple test to illustrate that his notifications were firing more often than he’d expect (seriously, I love the test driven breakdown of the problem), and made the project available on a GitHub repo. Unfortunately, you have to wade through 700 words, all setting the stage for the takedown of the block based API, before it’s made clear that the culprit is actually a bug in the code that removes his block as a notification center observer. And this is where we veer a bit off course.

Blocks Hate Selfies

Capturing self is a fairly well known “sharp corner” of using blocks. Avoiding it is also generally well understood. I have this defined as a code snippet, and use it regularly.

__weak typeof(self) wSelf = self

I thought the dangers of directly accessing ivars in a block was also well understood; but possibly not. Here’s a reminder: ^{ _myIvar; }; is actually like writing ^{ self->_myIvar; };. In this form, it’s easy to see why self is captured/retained. Is _myIvar an object? Guess what, the block doesn’t even retain it at all, just self.

Harmful API

I didn’t set out to write this as a takedown piece, but as a correction of facts, and encouragement of philosophy. Drew plainly states that -[NSNotificationCenter addObserverForName:object:queue:usingBlock:] is banned from his codebases, but to get there, had first had to cite a litany of tenuously linked data points. Sometimes documentation is wrong, file a bug report. Macros are sometimes tricky, blog about them. New syntax is sometimes confusing, learn about it.

Blocks can be hard; I suggest really learning about their memory implications, rather than dismiss API which uses them. Lots of API can be hard to use, LOTS of API does bad things when used incorrectly. Hell, even BOOL has some gotchas.

Remember that the root of this discussion was the importance of deregistering an observer, which is still a problem without block based notifications! Admittedly, retain loops can be challenging to debug. You know where else I see a lot of accidental retain loops? Classes implementing a delegate. I’ve seen many (mostly new) cocoa developers accidentally cause retain loops when they retain their delegate, but so far I haven’t seen anyone calling for a banishment of the delegate pattern.

Don’t Run With Knives

Since they were introduced, I’ve been commenting on (and bitten by) the vast amount of rope that blocks provide a developer with. But try to understand the common patterns and pitfalls of the tools!

With blocks, always tread lightly with self. With blocks that have a lifetime scoped to their parent’s lifetime tread really fucking lightly with self. Stop thinking about your long lived blocks as snippets of code, and start thinking of them as 3rd party objects — apply memory management rules accordingly.

Posted in Uncategorized | 1 Comment

UICollectionView’s backgroundView property is horribly broken

I want to love UICollectionView, I really do. But it continues to give me reasons to complain about it instead. I was working on some iOS 7-ish UI in our yet-to-be-announced project and trying to use the backgroundView property of a few collection views. To make the app feel more “alive”, I started occasionally updating this backgroundView to better reflect the current state of the app. Except, it just wasn’t working!

I went round and round for quite some time trying to figure out where my code was broken; then ultimately concluded that setting the backgroundView property simply would not be reflected once it had been set a single time. If I did something like the following, the result would always be a collection view with a red background, not the blue background I was expecting.

UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
collectionView.backgroundView = redView;

UIView *blueView = [UIView new];
blueView.backgroundColor = [UIColor blueColor];
collectionView.backgroundView = blueView;

I had accepted that backgroundView was broken, and planned to just put my own view behind the collection view (one that did what I asked it to), but I couldn’t get past wondering how this property could possibly be so broken. In my initial Googling, I had stumbled on an old GitHub issue for PSTCollectionView; the issue suggested that the backgroundView property had always acted odd when adding the provided view to the view hierarchy. How could this property just not work!?

The Big Reveal

I wish could say I did this part on purpose. I had Reveal open from some previous troubleshooting (Have you bought Reveal yet? If you haven’t, you should — it’s insanely useful), and lo and behold, right there in the exploded view I could see all the background views I had been adding. They were all just in the wrong place! The UICollectionView had been adding my provided backgroundView to the view hierarchy, but was never removing the old one.

Given our code above, the results in Reveal might look something like this:
Screen-Shot-2013-11-15-at-4.44.52-PM

Hilariously, if not completely expected, the collection view will stack as many backgroundViews, in reverse order, as you are willing to give it.
Screen-Shot-2013-11-15-at-4.47.28-PM

The Solution

Frankly, I think the best solution is to just ignore the backgroundView property all together. Instead, make the collection view’s background clear, and implement your own backgroundView; just throw a view behind the collection view.

It turns out, not unsurprisingly, the backgroundView property is workable as long as you manually remove it from it’s superview before setting it to a new value. Modifying our code from above, the following works as expected:

UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
collectionView.backgroundView = redView;

UIView *blueView = [UIView new];
blueView.backgroundColor = [UIColor blueColor];
[collectionView.backgroundView removeFromSuperview];
collectionView.backgroundView = blueView;

Screen-Shot-2013-11-15-at-4.53.24-PM-1

But wait, there’s more

Just in case you aren’t yet convinced that backgroundView meets the criteria for horribly broken, I have one more ridiculous example to provide. In preparation for this blog post and a bug report for Apple, I put together a sample project. It simply iterates over a short array of colors and creates colored views to assign as a backgroundView. Initially, I added this code to my viewDidLoad method, and my collection view was oddly — empty.

Of course, once again Reveal made this easy to investigate. And while I still have no hypothesis for how exactly the collection view managed to put itself in this state, you can see in the screenshot below that the cells have somehow been positioned behind my initial backgroundView.

- (void)viewDidLoad
{
    [super viewDidLoad];
	
	NSArray *colors = @[[UIColor redColor],
						[UIColor blueColor],
						[UIColor greenColor],
						[UIColor orangeColor]];
	
	for (UIColor *color in colors) {
		UIView *view = [[UIView alloc] init];
		view.backgroundColor = color;
		self.collectionView.backgroundView = view;
	}
}

Screen-Shot-2013-11-15-at-5.11.26-PM

Posted in Uncategorized | 4 Comments

Custom View Controller Transitions in Landscape

Recently, Jerry wrote about a really cool view controller transition we put together, SMLBookshelfTransition. As you can tell from that post, we’re really excited about all the possibilities this new API provides. You might have noticed though that Jerry made a point of saying he doesn’t usually write about brand-new API, because of the difficulty of doing it authoritatively.

Welp.

Being excited, we spent some time putting custom transitions into the project we’re working on. Everything looked good… until we rotated the device.

Turns out custom view controller transitions just plain don’t work in landscape. It seems that the system doesn’t apply the correct rotation transforms to the views involved: the container view that the transition context creates is always in portrait, even though the transitioning view controllers’ views may not be.

broken.m4v

Solutions?

If you google around enough, you may eventually arrive at this Developer Forums thread (Apple Developer account required). It suggests some potential workarounds, involving shuffling transforms around between the views involved. Make no mistake: this is seriously hacky, and likely to break with a future iOS update. Using these can make the transition look okay, but in my testing, rotations are still broken after the transition completes:

broken4.m4v

Instead, we took our own app back to using the slightly older-school view controller containment design. Making the presented controller a child of the presenting controller entails a bit more work to make sure the views all appear where they should, but it’s fully supported, uses the API as it’s designed to be used, and works as expected.

Conclusion

As far as I can tell, this stuff is just plain broken. I can’t in good conscience recommend that anyone use custom view controller transitions in any app that might ever need to go to landscape. Despite how cool the API is, it’s probably best to avoid it entirely in shipping projects until Apple fixes it in a new version of iOS.

Posted in Explanation | Tagged , , , , | 5 Comments

Bookshelf View Controller Transition For iOS 7

Update: View Controller transitions are terribly broken in landscape. I’d advise avoiding this if you need anything other than portrait transitions.

Few will debate the divisiveness of the aesthetics of iOS 7, but what many seem to have only just started talking about is just how API rich this latest release is. I generally hesitate to write about brand new API (it’s just too hard to do it authoritatively without having spent real time with it) but the new flexibility in view controller transition animations is somewhat near and dear to Joel and I.

If you’ve spent any time in the past writing code to do custom animations between view controllers, you likely already know how challenging it was to keep code cleanly isolated; and even when proper encapsulation achieved, there was the tendency towards whole separate tracks of willDisplay/didDisplay logic in parallel with the standard UIViewController flow. The encapsulation of the new UIViewControllerAnimatedTransitioning mechanism is so clean and pluggable that I hope (and expect) to see transition animators popping up all over GitHub. We’d like to help kick off this trend. (skip right to the code)

If you haven’t read up on the new transition API, I recommend first taking a look at Ash Furrow‘s recent post, Custom UIViewController Transitions, it’s a fantastic nuts and bolts guide to quickly getting moving with custom transitions.

SMLBookshelfTransitionAnimator

SMLBookshelfTransitionAnimator provides an easy to use “bookshelf” animation between two view controllers, similar to the well known transition in iBooks. The bulk of the animation code was written by Joel, originally as part of a redesign of my very first (and very old) App Store app, Peg Jump. Truth be told, I’m not even sure this rotating 3D box is a style we’ll see much of in the post iOS 7 world, but it still fits in nicely with a heavily stylized game.

Admittedly, the Core Graphics animation to achieve this effect isn’t the most complex animation in the world. All the relevant views are added to a CATransformLayer with transforms applied such that they are positioned in the form of a “box”, the transform layer is then animated 180° in 3D space. The original code was not terribly elegant, it ripped the backing CALayer out of the UIView for the front and back controllers. This animated superbly, but required some terribly ugly post-animation cleanup. Fortunately, iOS 7 provides some great new view hierarchy rendering API and SMLBookshelfTransitionAnimator uses these to provide the textures for the various sides of the animated bookshelf; no more view hierarchy patching necessary.

Easy Setup

There’s some boilerplate setup required to get the transition animator passed into UIKit (read Ash Furrow’s blog post if you aren’t familiar), but setting up the animator couldn’t be simpler. SMLBookshelfTransitionAnimator provides sensible defaults, you really only need to provide it with views for the left and right sides.

SMLBookshelfTransitionAnimator *animator = [[SMLBookshelfTransitionAnimator alloc] init];
animator.leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"left.jpg"]];
animator.rightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"right.jpg"]];
animator.dismissing = YES; // Required to automatically handle proper side view presentation

Options, we got em

SMLBookshelfTransitionAnimator allows customization of it’s duration, depth, perspective and rotation direction. Because we often create one off animator instances for presenting and dismissing view controllers, it also provides a couple of conveniences for automatically swapping the left and right sides to help aid in the appearance of a seamless, stateful, 3D transition.

As always, SMLBookshelfTransition is hosted over at the Spaceman Labs GitHub repo; and of course, feedback, suggestions, and pull requests are encouraged!

Posted in Uncategorized | 4 Comments

Compares

ComparesIconBig News.

As you may know, in October of 2012 Jerry and I left our day jobs in order to start Spaceman Labs. Our goal was to leverage our extensive knowledge and category-spanning experience on Apple mobile devices to build apps bursting at the seams with wonder and delight. The time from then to now has been full of learning experiences, many of which we have blogged about. But today we take our first public step towards our stated goal, with the release of Compares.

Compares!

There are plenty of ways to share a photo online, with your friends or perfect strangers. Whether filtered, auto-expiring, or creepily auto-identified, each picture is meant to tell a story larger than just the pixels that make it up. But some stories can only be told with two photos. Before and after. Compare and contrast. Young and old. We decided the world needed a photo sharing app perfectly designed specifically for side-by-side shots. From an onion-skinning camera to intelligently linked scaling and panning, Compares is just that. And since these stories are always made to be shared, we built a social infrastructure so you can connect with friends (from Facebook and the rest of life too) to see the compares they’re sharing. We’re even featuring the best of the best so you can find new people to follow.

IMG_0344

We’ve learned a lot in the process of making this app. We wrote our own backend, wireframed each screen, and controlled every aspect of the app from start to finish. This is exciting, and will spawn many blog posts in the future.

But for now, get the app and try it out! You can download it from the App Store. And you can see our (minimal) web client at compar.es. We’d love to hear what you think, which is why we put a “contact us” button in the settings. But if what you think is positive, we’d love even more if you’d rate and review it on the App Store.

Enjoy!

Posted in Software | Tagged , , , | Leave a comment

How To Support Old iOS SDK’s in Xcode 5

OH NOES, APPLE REMOVED SUPPORT FOR IOS 6 IN XCODE 5 *FIST SHAKE* !!!!

This is a sentiment I’ve seen a on twitter an awful lot in the last few days, and it’s not exactly accurate. The truth is, Apple does tend to encourage developers to link their applications against the latest SDKs; however, it is possible, with a tiny amount of hoop jumping, to use the new Xcode while linking against an SDK older than iOS 7.0.

The solution is simply to copy the old SDKs from the old Xcode to Xcode 5. Restart Xcode 5, and be sure you’ve changed your base SDK from Latest iOS to the specific SDK you’d like to build against, and you’re all set!

The iOS SDKs live here:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs

The Mac SDKs here:

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs

If you’ve already blasted your old Xcode in exchange for the shiny new Xcode 5, there’s no need to fret. As of now, Xcode 4.6.3 is still the version in the Mac App Store, and provides the iOS 6.1 SDK. Just go download it, and grab the SDKs out of it before reinstalling Xcode 5.

Update: @rekle points out that it’s possible to get older versions of Xcode from the Downloads area of the Apple Dev Center. Even once Xcode 5 hits the App Store, it should still be possible to get an old SDK version.

Posted in Software | Tagged , , , | 11 Comments

SMSquashView

Why Now? Why Me?

Lately we’ve been hearing a lot about adding personality and interest to apps with subtle animation, rather than with complex textures. As an animation guy from old times*, I couldn’t be happier about this new focus in iOS. There have always been lots of rich animation capabilities built into the frameworks, and based on nothing but the WWDC keynote, there’s bound to be even more simple, powerful animation API in iOS 7.

Of course, there’s still plenty that’s not easy. In the 2.5d world of iOS 7, things like SMShadowedLayer are more necessary than ever. Dimensionality is one way to add, if I may, depth to your animations. Another way is to infuse character and realism into the animated object.

Take a look at the principles of animation. Many of these – slow in and slow out, anticipation, timing – are provided by existing iOS animation APIs. More – arcs, follow through – are likely to be provided by iOS 7 APIs. But the most important item on the list, squash and stretch, is not addressed. This is a shame, as it’s a remarkably versatile technique. Used with a delicate touch, it can help the eye follow animation, making it easier to tell where an object is heading and at what rate. Used more liberally, it can add an appealing playfulness and character to the same animation.

I Fixed It For You.

SMSquashView and its backing class, SMSquashLayer, squash and stretch themselves automatically in response to motion. They will distort themselves longer in the direction of motion, and shorter in the perpendicular directions. The distortion is proportional to the velocity the object, and scaled such that its volume remains constant. In short: it does exactly what you’d want it to do, with no configuration required.

How Does It Work?

The math is pretty simple, if you like transformation matrices. Every time the layer’s position changes, we note the time and position delta from last time. Using that information we can calculate the velocity for the current frame of animation. We align a transformation matrix to the direction of travel using the same idea as gluLookAt, then scale according to the magnitude of the velocity.

Animation

Much the same as SMShadowedLayer, we won’t get enough information during implicit animations. Accordingly, we use exactly the same technique: set up a custom internal animatable property, tell the layer it needs to redraw when that property changes, but sneakily do our math rather than drawing when display is called.

Demo

Where Can I Get It?

Here. There’s lots of really interesting open source code on our Github account, so you might want to check out the rest while you’re at it. This code in particular is short and quite well-commented (I think!) and might make a fun read.

 

*I argued for exactly this use of animation in my 2008 WWDC session. Prescient! I am willing to speak about the future of graphics and animation at your conference too, just ask.

Posted in Code, Software | Tagged , , , , , , , , , , | 5 Comments

WWDC Blast

Early this morning we and our friend Alex C. Schaefer launched a new project of special interest to iOS and Mac developers. WWDC Blast is a free service to inform you via SMS the very moment that WWDC tickets go on sale. With tickets having sold out last year in under two hours, there’s no better time to automate this. We won’t spam you, we won’t sell your information, we just like the idea of keeping people as informed as possible. Check it out.

Technically, this project was a fun one. It’s the first web app we’ve launched, and while the guts aren’t incredibly complicated, we’re integrating lots of cool services and frameworks to make some magic happen. We’re using Heroku, Twilio, S3, Twitter Bootstrap, MixPanel, and some other cool stuff that isn’t even user-visible yet. And the list goes on.

Most fun of all is that we put together the whole thing, soup to nuts, concept to launch, in under four days. That’s right: the initial idea was broached Monday morning. We launched early early Friday.

Not bad.

Posted in Software | Tagged , , , , , , , | Leave a comment

Spatter and Spark

icon_150

Another year-and-a-bit, another successful client project! As of a few weeks ago, Polk Street Press shipped a brand-new storybook, Spatter and Spark. It’s a genuinely endearing tale of two best friends solving problems together in a way that five-year-olds will find endlessly entertaining. We do too. The story is engaging, the character design and illustration is phenomenal, and there’s just a ton of incidental interactivity to keep the experience fresh and engaging read after read. There are also IAP games and activities designed to teach a preschool skill set – they happen to be pretty fun, too. In a very cool innovation, the activities, and some in-story data, are optionally parsed on PSP’s backend to give parents an auto-updating report on their child’s educational progress.

Most importantly from the perspective of this blog, Spaceman Labs is responsible for all the code in the iOS app. We built on all the work we’d done for Goodnight Safari, and were able to make use of a lot of clever stuff we’d done, like cancelable blocks, audio-synced text highlighting, and animated character encapsulation. But we also developed the animation framework significantly. As it’s now Polk Street Press’s IP we can’t tell you too much about it, but we can say it delivers greatly improved fidelity, performance, and memory utilization (yes, more than just fixing leaks), all of which enables much more detailed, expressive, and long-running animations in the same app size and on the same hardware. We also did a lot of work on moving animation specifications out of code and into artist-maintainable XML, which allowed for rapid iteration without our involvement.

We’re really proud of this project. We love the work we’ve done, and we love the finished product. So far reviews on iTunes seem to agree. Check it out (on the App Store and at Polk Street Press’s website) and let us know what you think.

Posted in Software | Tagged , , , , | Leave a comment