Category Archives: iOS

Frameworks Need Better Logging

Over the past couple years, I’ve worked with quite a few third-party frameworks. These experiences have highlighted a significant deficiency common in many frameworks; most frameworks suck at logging. More recently, I’ve had the chance to build a few frameworks from the ground up, so I’ve used those to explore how logging could be done differently.

Bad: NSLog

There are two common ways to handle logging inside a framework, and both of them stink. The first is “good ol’ fashioned” NSLog() or print/f(). As a framework does its work, it merrily peppers the console with diagnostic or error information. These messages are usually helpful during development, but this pattern leaves a lot to be desired when customers report bugs and the console messages are absent.

Also Bad: Another Framework

The second is the utilization of a logging framework like CocoaLumberjack.1 Logging frameworks are great because they offer lots of flexibility, including mechanisms for collecting and sending logs in bug reports. Seems great, right? The framework can push error messages into the log, and my app can bundle those log messages up when it sends in a bug report. Except that this app doesn’t use CocoaLumberjack – it uses NSLogger. What’s worse is that another framework in the app uses GTMLogger. All of the sudden, there are three logging frameworks and they don’t work together.

A Simpler Way

Great frameworks should strive for zero dependencies. Since integrating a logging framework into your framework is contrary to that goal, let’s explore a simple approach that gives your framework’s integrators more control of logging in their apps.

The approach below is pretty simple, but after using it a number of times in frameworks I’ve helped build, it has proven quite effective. The example I’ll give is written in Objective-C, but the pattern translates to Swift nicely.

Public Interface

Here are the public parts: a register and unregister function, along with a callback signature. I also prefer to provide basic levels, but try not to get too carried away – keep it simple.

App Integration

Early in the process lifecycle, the app can register a callback with the framework. This block of code gets called any time the framework produces a logging message. Since a level is passed along, the application can determine how to either map the message to another logging system, or simply discard it.

Framework Internals

The internals of the framework’s logging are even simpler: a basic C function for producing log messages. This, of course, could be improved to use preprocessor macros to include inline file names, line numbers, and compile-time configuration for log levels.

Any time the framework needs to produce a log message, it simply calls the log function:

Logging Implementation

Here’s the basic logging implementation from inside the framework. Obviously, your version may require more safety checking (locks around the callback, etc.) or more sophisticated dispatching to protect certain threads and queues, but this should get you started.

Hopefully this gives you some ideas about how you can improve logging in your own frameworks to make integration even easier. If you have questions or want to share some ideas, you can find me on Twitter.

  1. I’m not picking on CocoaLumberjack at all here – I use it in my apps, and you should consider doing so as well. It’s a great, battle-tested framework.

The Cost of Swift

Before I get started, I need to preface this essay with a few important points:

I really like Swift. I’ve built quite a few apps with it, both at work an on my own. Astra is almost entirely written in Swift, with only a few classes that touch Core Audio written in Objective-C.

My opinions are my own – they don’t reflect those of my employer or my coworkers.


Swift, a language that is less than three years old (publicly), has gained an amazing amount of momentum within the iOS/Mac community, as well as the broader programming populace. It boasts some ambitious goals of speed, safety, and expressiveness. Naturally, Apple’s emphasis on the language has also bolstered its adoption.

After building my own product in Swift and watching other product owners struggle with a common issue, it’s time to address a problem with the language: the cost of using Swift. To demonstrate, I’m going to share a story.

Astra 1.0

Astra was initially written in Swift 2.3. In the interest of releasing version 1.0 of the app, I delayed the Swift 3 migration last fall and shipped with Swift 2.3. As the product owner, I had to make a conscious decision about when I was going to bite off the Swift 3 migration, and getting the app in the market outweighed the debt of an older Swift version.

Once version 1.0 shipped, I began working on the next minor version of the app – a few new features, some enhancements – typical dot-fix things. As anticipated, a patch release needed to be shipped, so I fixed a couple critical bugs in 1.0.1, and then enjoyed the holidays with my family.

Side Projects Cost Time

Astra is a side project; I have a full time job, as well as a family and other “real world” responsibilities. When I get time to work on side projects, it’s usually for 30-60 minutes at a time, and almost always after 10:30pm.

All projects have some sort of constraint. It’s usually budget. Since I work on Astra for “free,” my constraint isn’t budget, but time. Each minute I spend working on it takes me away from my family, sleep, other hobbies, or a whole list of other things I really need to do.

The Swift 3 migration took me four nights, somewhere between 6-8 hours in total. This effort spanned a couple weeks, since I don’t necessarily have consecutive days to work on Astra. This was relatively quick, compared to other stories I’ve heard and witnessed.

Once I had code that compiled, I spent another couple nights getting the app to work again. In the end, I spent well over two weeks migrating the app to Swift 3.

This amount of time has very real consequences, but users will never see those efforts as direct  improvements in the product.

I track Astra bugs and features in Trello, and I try to keep each card small enough to complete in one sitting. I keep the list prioritized, but when I know I have a small amount of time, I hunt for a card I know I can do all at once.

The Astra board didn’t change for over two weeks because of the Swift 3 migration. That was two weeks I didn’t get new features or enhancements built, or customer-reported issues fixed. I was simply agreeing to proposed changes by the tools, and then fixing the problems it created along the way.

Developer Happiness

The language an app is written in does very little to serve the needs of a customer. There are weak arguments that some languages result in fewer crashes or bugs, but that doesn’t play out in reality. A product built with proper testing practices always demonstrates a higher level of quality in my experience, regardless of language.

Fundamentally, a developer’s role in app development is to translate interaction and visual designs into functioning software. That means it’s their job to deal with unexpected errors and failures. It’s risk management. These risks also have to be balanced with product timelines – press events, market changes, and competition.

When the ability to ship a product is affected by a tool or programming language, a product owner has to question if it is the right tool. For software, the programming language is a means to speed up development of a product. For iOS, Swift keeps developers from having to write in C or Assembly, much like using UIKit keeps them from having to develop graphical interfaces from scratch. And while Swift is pleasant to use as a developer, it doesn’t provide tangible benefits to a product owner, much less end users.

Apple’s Timeline

Swift is both an academic venture and a product for Apple. It is mastered by two conflicting objectives – to aggressively evolve and simplify difficult development tasks, while marching along a scheduled release cadence. Caught in the middle, developers who choose to use the language end up with code that breaks regularly.

Last week, we also learned that ABI stability has been deferred from Swift 4.

Apple has been aggressive in deprecating versions of Swift, which means Apple dictates Swift migration timelines, and not the product owner. The next release of Xcode is expected to remove support for Swift 2.3. In the case of Astra, this hasn’t been a problem yet, but easily could be.

Emergency Hotfixes

I had to spin a quick 1.0.2 release to Astra a few weeks ago. If you’re following along, you realize that meant fixing a bug in Swift 2.3. In addition to fixing the bug quickly, I had to decide how to get the the fix in both Swift 2.3 and Swift 3 branches. In the end, I implemented the bug fix twice, due to how divergent the project was after other refactoring.

With a fix in place, I had to build the code. Fortunately, I haven’t jumped to Xcode betas, so Swift 2.3 is still supported on my build machine. What if the timeline had played out differently? Sure, Apple still allows submissions from old Xcode versions. That would have meant lost time setting up an older Xcode version. There’s even more time I’m not building features or fixing bugs.

The choice to use Swift imposes a lot of otherwise unnecessary decisions and time costs.

Some Guidance

Here are a few points to consider as you decide how to embark on a new project, whether it be personal, contract, or a product at work.

If the project is intentionally going to be short-lived (less than a year), use Swift. You’re already in the realm of quick and dirty. Constrain yourself to specific versions of libraries, and make sure you clearly communicate this approach is being used to all stakeholders.

For something medium-term (1-3 years), cautiously use Swift, but avoid third-party code. Projects with Swift frameworks need to match Swift version throughout. This means carefully matching versions of frameworks you’re pulling in, especially during migration periods. This is an easy place to burn a lot of time.

If you’re building a framework (especially a commercial one), use Objective-C. Do not impose unnecessary burden on apps integrating your library. Carefully design your interfaces for elegant Swift integration, but implement your code in Objective-C.

For a projects anticipating long-term development, or that have the scrutiny of investors, or are the primary means of putting food on your table, seriously consider Objective-C. It may not be glamorous or flashy, but it is reliable and proven. Seize the opportunity to demonstrate wisdom and expertise to clients by articulating a case for avoiding new shiny things.

The Future

As a developer, I’m very excited to watch Swift continue to evolve. I’m deeply impressed by Apple’s approach, both in making the language open source, and the level of public collaboration they’ve continued to demonstrate.

As a product owner, I have to be cautious when selecting tools. If it can’t be directly translated into value for my customers, then a flashy new tool or language isn’t the best choice. Today, Swift’s breakneck pace and deprecation cadence make it a risky choice for a product, whether it be a side project or a breadwinner.

Friends and Family Apps

When the App Store first launched, mere presence was enough to ensure at least some small amount of success. Today, things are much different. A great idea with good execution will still struggle to make a splash in the App Store, unless the stars are perfectly aligned. Even then, it’s usually more about who you know and the press you can drum up.

Here’s a conversation I had with Kevin Harwood last week:

Kevin: “How was the [Pactola] launch?”

Me: “Eh… I knew it was going to be light. It’s pretty niche.”

Kevin: “Friends and family?”

Me: “Yep.”

I wasn’t kidding; I knew full-well going into the project that I was going to have a hard time selling an application that provides a rest API for sending push notifications. There are similar free apps, and the target market is pretty specific. To make matters worse, I spent no time marketing or reaching out to press folks who might want to do a review. These are pretty basic things, right? You’re probably asking why I bothered to build the app.

Here’s a secret for anybody interested in iOS development: employers don’t care how many units you’ve sold on the App Store. They care about what you’ve built: how you did it, what you learned, the extra attention to detail you gave, and how all of those things can help their team.

So why did I build Pactola?

  • The server is built in Go. This was my first experience with the language.
  • Jenkins deploys the server automatically when I push to master. The iOS build is also on Jenkins to ensure I’m building from reproducible sources, and not just a point-in-time on my local workstation.
  • The deployment script relies only on SSH and bash, minimizing VPS setup time and overall dependencies.1
  • The iOS app uses Storyboards and Auto Layout (I’m coming off of two years where I was primarily focused on OS X development targeting 10.6 and up; no ARC, no Auto Layout, and no Storyboards)
  • Screenshots are automated, thanks to ui-screen-shooter. I had to learn about UI Automation and come up with a strategy for creating real data in the screenshots.2
  • I disciplined myself to write out tasks and issues, and then tracked them on a Trello board. When the tickets were all in the Done column, I shipped. I also have a nice backlog of future ideas and nitpicks.
  • I used Apple’s TestFlight system for the beta. This was my first chance to use it, and I got a good feel for how it compares to the legacy TestFlight system.3
  • I’ve now shipped an application that uses APNS and have a strong working knowledge of the system, its capabilities, and have some ideas for leveraging it in other apps.
  • I tried to stick to a Ninety Days rule, though I didn’t account for changing jobs.

So while I may not ship very many copies of Pactola, I’d say there are a few interesting things I could talk about in an interview. I’d highly recommend finding something you’re unfamiliar with and building your own Friends and Family app.

  1. Since Go apps are statically linked, there are no other dependencies on the host system; pactola-server runs on any Linux system once my keys are there to accept the ssh deployment.
  2. The app contains no extra magic for this, except for registering as a special known-device when running on the simulator. The server populates the data for that special device. And yes, there are Go tests for that special behavior.
  3. Given the end of the original TestFlight, that proved to be a good use of time.

iPhone 6 Plus: One Month Later

The iPhone 6 Plus is one of the most curious devices Apple has built in recent years. The largest iPhone ever built, it evokes a sense of awe, confusion, and concern. In some ways, it suffers a bit of an identity crisis in the iOS family, as it behaves like an iPad sometimes, but is also clearly an iPhone.

After carrying it for a month, I’ve returned to my beloved iPhone 5s as my carry device. Since most reviews are written after only a few days of usage, I thought it would be interesting to share some thoughts on the iPhone 6 Plus after using it exclusively for over a month.

I’m in the unique position of possessing an iPhone 6 Plus that I don’t own. I would probably be more biased toward the device if I had paid money for it. It’s liberating to be able to evaluate the phone without worrying about the regret that would come with a purchase I don’t like. I’m also very grateful to be employed by a company that is excited to explore new devices and technology, and that paid for the phone.

To be clear: the views and opinions contained within are mine alone.

The Good: Camera, Screen, Apple Pay, Battery

The camera is absolutely wonderful. Without question, the camera is what kept me from ditching the iPhone 6 Plus sooner. The camera produces the most vivid colors I’ve ever seen from a phone, and rivals a lot of the pictures we’ve taken with our DSLR. With minimal effort, it can capture moments precisely and beautifully, which is incredibly important and valuable to me as a parent. I snapped some wonderful pictures of my children this past month, and they’re some of the best photos I have in our library.

Good morning, Austin

A photo posted by Thaddeus Ternes (@thaddeus) on

The screen is staggeringly large, which makes the experience of some apps simply wonderful. I watched nearly all of the Dollhouse series on Netflix with the iPhone 6 Plus; it’s a fantastic device for watching TV shows, and is much more comfortable to hold than my iPad mini. The detail in HD content is astonishing, and the backlight has no problem producing a blindingly-visible image in almost all lighting conditions.

Over the course of a month, I had a few opportunities to try Apple Pay, and was always pleased with how simple it was to use. I’m excited for the future of payments with NFC, and I have enough confidence in the security of Touch ID to use the feature in places where credit cards have previously given me pause. 1

What I’ll miss most from the iPhone 6 Plus is the battery. I could carelessly leave the device unplugged overnight without a second thought; I routinely went over two days without charging the device, especially when using my desktop to stay on top of my Twitter timeline. The battery life is incredible.

The Bad: Size, Flickers and Glitches

The biggest2 problem with the iPhone 6 Plus is the unwieldy size. One-handed use is almost impossible for me, even with my typically-large adult male hands. I found myself constantly worrying about dropping the phone, which is something I’ve never had much concern over with my smaller phones. Of course, this anxiety probably lead to the increased fumbles I had with the phone.

The weather in Austin has finally cooled down enough that I’ve been wearing jeans for the past month. The iPhone 6 Plus fits uncomfortably in my jeans pocket. I don’t notice it when I’m walking around, but have to take the phone out when I sit at my desk, drive, or play with my kids. It presses into me when I sit, and is impossible to take out of my pocket once sitting. For somebody carrying a phone in a bag or purse, this probably wouldn’t be an issue, but using an iPhone 6 Plus from a pocket is awkward at best. I’ve always carried my iPhones without a case, and while a case may have alleviated some of the fumble anxiety, it would undoubtedly make the pocket experience even worse for me.

The phone also doesn’t fit in a lot of places that are convenient to set a phone. Two of my favorites are cup holders in the car and the small tray on HEB shopping carts. Cup holders make a great bullhorn while I use Maps to navigate my new city, and the shopping cart trays safely cradle my phone while shopping3, keep me from fumbling the phone in and out of my pocket. Neither of these stashes worked with the iPhone 6 Plus, simply because of the size.

While the dimensions of the device can’t be changed, there are some other issues that Apple can fix with software updates. The iPhone 6 Plus exhibits more flickering views, rotation glitches, and animation stuttering than I’ve seen with latest-generation hardware, even when running the latest iOS release.4 In fact, I’d dare say my 5s feels consistently smoother.

One of the most frustrating issues I ran into was the inability to swipe open the camera from the home screen; when I would try to open the camera, the home screen would slide up about half an inch, and then drop back down to fully-locked. I missed more than a couple photos because I couldn’t get the phone unlocked soon enough. This may have to do more with iOS 8 than the iPhone 6 Plus, which I’ll understand better as I get back to my 5s as a daily carry.

In a lot of places, the curved edges of the phone enhance the user experience. Swipe gestures to go back in the view hierarchy are wonderful on the phone, when they work. More than a few times, I had trouble getting the gestures to recognize, which is an issue I’ve rarely experienced on my 5s. The fit and finish of the device is really wonderful, and it compliments the software in a way only Apple can.

My Favorite Size

I’ve seen a lot of praise for the iPhone 6 Plus, and most of the favorable reviews echo what I found: the screen if beautiful, the camera captures stunning images, and the promise of simple, secure payments is here with Apple Pay.

I’d love to see Apple roll the great things about the iPhone 6 generation into a hybrid with the last generation: smooth edges, thin profile, expected camera improvements, and stunning battery life. In some ways, that’s pretty similar to the 5th generation iPod: thin, smoother edges, aluminum back, and a manageable size. A reasonable mix of the things universally loved with a compromise on the physical size would be a welcomed upgrade for me. Until then, I’ll stick with my trusty 5s.

Oh, and reasonable storage. 16 GB is nuts.

  1. The gas station where I used Apple Pay most often also required a signature, which showed a fundamental lack of understanding in the technology by some payment systems.
  2. Sorry… I had to
  3. And being rate-nagged at the grocery store
  4. 8.1.1, as of writing

iOS Configuration with .ini

It seems like an unlikely candidate, but I’ve recently started using .ini files for iOS app configuration. I know what you’re thinking: “Wait – are you talking about those text files on Windows?”

Yep, those.

Common Formats

Let’s have a quick look at some of the most popular options for expressing configuration in text format.

XML

Historically, XML is probably the most popular choice – it’s widely supported, well understood by most developers, and expresses hierarchy quite well. In fact, plists are most often represented in XML, so they’re a natural choice for iOS and Mac developers.

<configuration>
    <views>
        <view>
            <!-- displayed when app launches -->
            <name>main</name>
            <textcolor>#0000ff</textcolor>
            <backgroundcolor>#ff0000</backgroundcolor><backgroundcolor>
        </backgroundcolor></view>
        <view>
            <!-- contains copyright, version information -->
            <name>about</name>
            <textcolor>#777777</textcolor>
            <backgroundcolor>#afafaf</backgroundcolor><backgroundcolor>
        </backgroundcolor></view>
    </views>
</configuration>

JSON

JSON is more fashionable these days, since it translates to dictionary/map structures quite well, and is also supported in most modern runtimes. It handles types very nicely, including lists and nested objects. It’s also noticeably lighter than XML, which makes it great for sending over networks.

{
    "views" : {
        "main" : {
            "textColor" : "#0000ff",
            "backgroundColor" : "#ff0000",
        },
        "about" : {
            "textColor" : "#777777",
            "backgroundColor" : "#afafaf"
        }
    }
}

You’ll notice the lack of comments – one of JSON’s biggest drawbacks for configuration is not being able to place comments in a file. There are some parsers that will accept certain sequences as comments, but that’s highly variable. For what it’s worth, the following NSJSONSerialization example produces an error:

NSString *json = @"{ \"rawr\" : \"bam\" /* no comments */ }";
NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
NSError *parseError = nil;

id obj = [NSJSONSerialization JSONObjectWithData:jsonData
                                         options:0
                                           error:&parseError];

NSLog(@"parseError: %@", parseError.localizedDescription);

Output:

parseError: The operation couldn’t be completed. (Cocoa error 3840.)

YAML

YAML is probably the least common, though quite popular within certain development communities. The syntax is very readible, and it’s arguably the best at representing hierarchy. It actually has quite a bit in common with INI, which makes it a compelling option for cases where .ini may be too light on features.

---
mainView: #displayed when app launches
    textColor: #0000ff
    backgroundColor: #ff0000

aboutView: # contains copyright, version information
    textColor: #777777
    backgroundColor: #afafaf

YAML has a large featureset, which is a contributing factor to the complexity of most parsers. YAMLKit looks like the best parser for Objective-C, but requires LibYAML. LibYAML is a classic configure/make/install project:

$ ./configure
$ make
$ make install

If you were already going to be supporting cross-platform software, this wouldn’t be a big deal (though you’d also probably not care about the Objective-C aspects either), but we’re specifically talking about iOS here, so this is a fair issue. Getting this built for iOS isn’t as trivial as the steps above, so roll up your sleeves for a cross-compile if you head down this path.

A Common Problem

Each of the examples above has a subtle problem that would cause most parsers to fail, typically leaving the entire document unusable. In each case, the error is so understated that it may only be caught by a runtime error.

  • XML: careful to properly close those tags!
  • JSON: curly here, curly there, and oops! too many commas
  • YAML: derp – whitespace requirements around comments

Of course, the delicateness of these syntaxes is ultimately up to the implementation of the parser in use (and how strictly it conforms to spec). As you’ll see in a moment, I’ve skirted around those problems by implementing the ini parser myself.

INI

Let’s see what an ini file looks like.

[mainView] ; displayed when app launches
textColor = #0000ff
backgroundColor = #ff0000

[aboutView] ; contains copyright, version information
textColor = #777777
backgroundColor = #afafaf

There are a few things to like about the .ini version of this configuration. The file is incredibly readible. I prefer the section headings to separate objects in the file. The syntax isn’t dependent on whitespace, so there’s lots of freedom in formatting. In fact, the syntax of ini is so simple that there are relatively few things you can do to break it. When things do break, they typically only ruin the current line, which doesn’t prevent the rest of the file from being parsed.

BTINIParser

Of course, it wouldn’t be fair to try and advocate such an absurd notion without giving you the chance to try it for yourself, so I’ve included BTINIParser in my BTToolkit project. It’s very much a work-in-progress, but includes tests and is powering a theming engine I’ve built into a little iOS project I’ve been working on. It could use a few more public methods, as well as some error reporting, so fork and submit PRs, please.

Try It Out

Hopefully this has piqued your interest in exploring an uncommon file format for iOS developers. If you’re working on an app that supports themes or other variable runtime definitions, it’s definitely worth a look. The ini file is a nice option that easily covers the key-value pair requirements of most configuration needs.

Let me know how it works out by chatting with me on ADN or Twitter.

Was Touch ID Steve’s Last Project?

There has been lots of speculation that the iPhone 5 was Steve Jobs’ last major project at Apple. That has always felt pretty shallow. The iPhone 5 was a significant redesign, but certainly not the groundbreaking kind of release that would consume a visionary’s thoughts.

This answer on Quora has me wondering if it was actually Touch ID. He certainly had to be aware of the project if it was in-progress while he was at Apple. The vision necessary to see something like that as far back as 2008 is very much in the realm of Steve.

Apple has taken a very slow and methodical approach with the release of Touch ID.  We can see that there was a tremendous amount of amazing work that has gone into this project.  All of this convergence took over seven years of very hard work. It includes many patent applications, the acquisition of AuthenTec, the selection of the A7 processor and the integration of the TrustZone suite all baked together into what we now know as Touch ID.

Sounds about like Steve to me.

Via Daring Fireball