I was troubleshooting some iOS crashes with the team today and remembered this post I’d saved by Matthijs Hollemans, My App Crashed, Now What? It’s a great introduction for anyone starting to pick apart all the wonderful ways an iOS app – and more generally Objective-C – can break.
There’s plenty here to make me yearn for the helpful stack traces in Java once in a while (possibly the only thing I prefer about Android development…), but it’s all good stuff to know if you’re supporting a widely used iOS app in production. Enjoy!
After updating from Xcode 5 DP2 to DP3 I found that several storyboards in my iOS project could no longer be opened, and would also prevent the project from building, with an error like:
The document “MainStoryboard_iPhone.storyboard” could not be opened. Could not verify document content.
Interestingly it did not affect several storyboards which hadn’t been touched in awhile, and for those exhibiting the problem some trial and error revealed that deleting the table view inside certain view controllers fixed it. Of course, recreating table contents with all of the layout and segue intricacies is not ideal so I poked around further using Open As Source Code and noticed that the suspect tables had become tableViews inside a viewController (versus tableViewController) which was now failing verification.
I’ve actually run into this problem before when a developer manually added a UITableView to a plain UIViewController, either by accident or because they changed their mind partway through the design, and saw unintended side effects. But in this case it seems to have started out just fine and been mangled by Xcode 5 somewhere along the way. In any case, using Open As Source Code and manually changing the involved XML tags fixes the problem, allows Xcode 5 DP3 to open the storyboard, and most importantly preserves all the content without deleting anything or disabling auto layout.
For example, change:
<viewController storyboardIdentifier="MyScreen" id="Brq-Jb-DRf" customClass="MyScreenViewController" sceneMemberID="viewController"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="70" sectionHeaderHeight="22" ... </viewController>
<tableViewController storyboardIdentifier="MyScreen" id="Brq-Jb-DRf" customClass="MyScreenViewController" sceneMemberID="viewController"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="70" sectionHeaderHeight="22" ... </tableViewController>
If you’re seeing this error without the scenario above there may be other similar problems that now fail Xcode validation which are also solved by a quick fix in the storyboard XML. I’d recommend deleting scenes or objects in the storyboard until things work, then add back a new/empty version of the object causing the problem, compare source, and if it’s a simple fix then revert and update the XML yourself similar to above.
Please comment if you find any others and I’ll add them here.
As a runner and first-time marathoner last fall I was shocked along with the rest of the country at the attacks out of nowhere at today’s Boston Marathon today. I can’t imagine being caught in the midst of this only feet from the finish line. It’s such a great race that won’t ever be quite the same after this. There aren’t really words to describe how disgusting it is for anyone to be killed or maimed at such a fun, open, and historic event. But, I still want to run it and know they’ll pull it together, stronger than ever, in the years to come.
I also realized I’ve now posted twice in row about something terrible happening with crickets in between. This isn’t intentional, and I actually have plenty else going on that’s blog-worthy, but it turns out living life takes precedence over blogging about it sometimes. Even so, I’ll try to stop procrastinating and get it up here. Starting tomorrow.
For now my thoughts are with the runners, friends, and families in Boston tonight.
I ran my first marathon, the Boulder Marathon, last week! After an intense but super fun past couple months of seemingly constant running when I wasn’t working, sleeping, or spending weekends and evenings with family (hence the lack of blog posts) I was totally ready and super proud to finally finish a big one.
I’ve been running casually since the end of college, at first intermittently between travel for work – something I did a ton of the first couple years after school – and then more consistently after getting married and being in town most weeks. But for a couple years this was once or twice a week for a mile or two at most without any thought put into distance, route, or pace, and I had no interest in signing up for a real race. Heck, living around Boulder I’m not sure that was even enough to call myself a runner!
Three events really changed this for me. First, watching the 2008 Summer Olympics four years ago which were first games where I was also running on a regular basis during them. I especially loved seeing Michael Phelps dominate, and after his last gold medal thought to myself, “if he can do that I can actually be more than half-assed at all these runs”. So I pulled up Google Maps and specced out an actual 5k, looked at the clock, ran it, and when I got back figured out my total time and pace.
Second, RunKeeper. This amazing app is an iPhone lover’s ultimate running companion. It’s beautifully designed, completely free of adds and other garbage (in both the app and website), and most importantly Just Works. After stumbling on it I was instantly hooked on running with my iPhone instead of the iPod Nano (despite the bulk – I have no problem with an armband!), hearing my distance and pace real-time each mile throughout my runs along with looking at my route afterwards. I know this is cliche to everyone who’s run with a stopwatch well before the existence of such niceties but as someone who entered adulthood with the advent of stats and achievements in online games, social media, and everywhere else it was perfectly natural and fun to have this immediate feedback as part of my runs. In fact, I craved it and immediately started getting much faster and more consistent. In no time I could feel my pace within +/- 30s per mile and knew the distances of every corner or landmark along the local paths. As RunKeeper added achievements proper I loved hitting them and it fueled me even more.
Third, having a kid. This was the most unexpected catalyst because I thought in advance the post-partem craziness would put running on hold, and depending how much free time I had left maybe even kill it altogether. But I was itching to run the day we came back from the hospital (and had a chance to, thanks to knowing grandparents who took care of everything for a couple hours while we did whatever we wanted that first day back!), and kept doing it whenever I could squeeze time in around lack of sleep and new baby wowness. Even more than before it became a crucial relaxation point of the day any time I could get a run in, and as opportunities for lots of other “fun” stuff evaporated it was one thing I could do solo and keep adjusting around any schedule. Then as soon as Cayden was old enough to ride in a BOB stroller, first in the little infant carrier and then eventually by himself in the big seat, runs became something even more amazing: a ridiculously epic trifecta of doing something fun that’s also great exercise for myself, an activity I can share with my son that he absolutely loves doing with me, and giving mama a break to do whatever she wants by herself while we’re gone.
If you don’t have kids you will not understand how rare and precious such things are, and I was totally surprised and thrilled at how much Cayden enjoyed it. He’ll ask to go on runs now, babbling, singing, pointing, laughing, or even snoozing the whole way, cheering when we get home, and never getting bored or complaining. I don’t know how he does it when he can’t even sit still for two minutes most other times, but I’m lucky. So within a few months of being into serious runs with a kid in tow I decided to up my game a little more and sign up for a real race, the Bolder Boulder. I ran it with a respectable time and kept running longer and harder after it, finishing the Sombrero Trail Run, Colder Boulder, and a few others over the next year.
By that point I’d had over a year of really solid running under my belt and was ready for another step. So this past spring I decided it was half marathon time, and I ran three of them along with the Bolder Boulder again in between. The first couple were mediocre, but by the third I was nailing my pace and ran every mile consistently getting in under two hours. At that point I decided it was time for the big goal: a marathon. Half marathons had always seemed in easy reach based on a starting point of being fit and running easy 10ks, but a full marathon was pretty daunting. It just didn’t seem like a whole lot of fun to run for that long, and even worse to do it for all the training lead up to it. But after a couple 15 mile+ hard runs pushing a BOB stroller the whole way (which I’ve come to realize is at least a 20% difficulty hit, but awesome way to make every step of a long run really count!), I knew I could do it. So I signed up for the Bolder Marathon and started putting in the rigorous mileage necessary to be more fully prepared than the half-assed training I had put in for any of the shorter races leading up. My first marathon was not going to be a DNF, and also not going to be walked through the second half!
Thanks to a great summer of training, especially all the long runs with running buddy Cayden along in the BOB and mama’s patience as the schedule did get crazy a few weeks, I went into race day totally ready. The weather was perfect, with beautiful fall colors on the Boulder backroads, clear skies, 50-60 degrees the whole time. I even had a random stray goat run along with me for a couple miles which was a hilarious little break from my usual focus. The first 20 miles felt great, and I actually blew through my half marathon PR over the leading 13. But if there’s one thing I’ve heard about marathons that rang true, it’s that they are a 20 mile warmup followed by a really fucking hard 10k. It was just stupid how drained I was over the last few miles, even with all the water, gatorade, and gels I packed in on schedule, and by the final mile I was really on my last legs. Still, that’s not unlike how the last few miles of my first half marathon felt, and more importantly I felt pretty great after a nap through the rest of the day, only a tiny bit of soreness through the rest of the week, and the next weekend I was out again enjoying a casual five mile run with Cayden.
So, I can do marathons, and they don’t make me hate life during or after – meaning I can probably push even harder. I’ve been thinking about it, and rather than just do more marathons I’m considering a couple goals: qualifying for and running the Boston Marathon, and really kicking it up to do an ultra marathon. Some high elevation or other particularly difficult marathons seem fun as well, and will give some nice variety to the slew of them I’ll probably run on the way to these goals, but having them out there gives me something else to focus on. That is, when I’m not working, sleeping, or raising a kid… just like when it all started! I will try to write more about it though. Reading about the running adventures of others has reminded me that it’s a worthy topic to pour myself out about every once in awhile.
In the meantime, I’m super proud to have knocked the marathon off the list and will now say without hesitation – even in Boulder – that I’m a runner.