You’re an iOS developer. You’re excited about all the great new features iOS 10 brings, and you’re eager to implement them in your app. You want to start working on it right now so that you’re ready to ship on day one. But that’s still a few months away, and until then, you have to keep shipping new versions of your app every few weeks. Does that sound like you?
Of course, you can’t use Xcode 8 to compile your shipping app — it wouldn’t pass App Store validation. So you split your project into two branches, one stable, another for iOS 10 development…
And inevitably, it will suck. Branching works beautifully when merely working on a feature for a while. But try maintaining a huge branch for many months, with changes spread across the whole codebase, while the main branch also evolves, and you can brace yourself for some serious merging pains. I mean, have you ever tried to resolve
.xcodeproj merge conflicts?
In this article, I will show you how to avoid branching altogether. For most apps, it should be possible to have a single project file that will compile for both iOS 9 (Xcode 7) and iOS 10 (Xcode 8). And even if you do end up branching, these tips will help you minimize the difference between your two branches, and make syncing them less painful.
Read on »
guard is one of my favorite features of Swift 2. It’s one of those subtle syntactical constructs we could totally do without. And yet having it is such a delightful win. It makes our methods cleaner and easier to read, it helps express the “early exit” intention, and adds a little extra safety.
However, it’s important to learn and understand how to use
guard properly. It has its place, but it’s not meant to replace
if let in all cases. No matter how great
guard is, it can easily be misapplied and forced into places where other constructs do a better job.
Here are some basic guidelines for when to
Read on »
guard, and when not to:
A year ago, not long after Swift became a thing, I noticed a tendency among programmers to write it the way you’d write Objective-C. I thought that Swift was a different language, with different syntax, philosophy and capabilities, and so we should develop new conventions and approaches to it. I responded with Swifty methods, where I argued for a better, clearer way of naming things. Then, some time later, I started the Swifty APIs series to put those ideas in practice and explore how to design easy-to-use interfaces.
In the first article in said series, we took the
NSUserDefaults.standardUserDefaults().setObject("red", forKey: "color")
… and we made it look like this:
Defaults["color"] = "red"
The result was clearer, less verbose, and nicer looking than the original. We fixed some consistency issues and made it all fit better with Swift. This felt like a significant improvement.
And yet, as I’ve been actually using the new API, and learning Swift along the way, I realized that it wasn’t actually very Swifty at all. I drew inspiration from Ruby’s and Swift’s syntax in designing it, and that matters, but we didn’t improve it on a semantic level at all. We only put a Swifty coat of paint on a fundamentally Objective-C-like mechanism.
Read on »
Back in March, I gave a talk named “Swifty methods” on the Swift Summit conference in London. It’s a shorter, more compressed and refined version of the arguments I was making in the essay with the same name as well as the Swifty APIs series. I think it went quite well, so I encourage you to give it a watch on the Realm website:
(I wish I could just embed the YouTube video here, but the Realm team went to great lengths to nicely synchronize the recording with the slides, so it works better on their website)
Read on »
Hey, this is an old post! If you’re on watchOS 2, you probably don’t need these optimizations. I encourage you, however, to read my view model diffing post, which continues to be useful even with a native SDK.
In Practical and efficient WatchKit tables with view model diffing, I presented a way of making Apple Watch apps that simplifies application code and results in superior performance by moving UI updating logic to the framework layer and making it smart about pushing updates over the radio.
Another way you can reduce iPhone—Watch traffic and make your app faster is by loading tables lazily. Instead of displaying everything at once, you only load a portion of the data, and then add more rows as needed. This can make a huge difference.
However, even though it sounds simple on paper, lazy loading can be surprisingly hard to do by hand. It’s trivial when you have relatively static data (for example, the calendar rows in Things). But when you have a combination of cached data and network fetches, and you allow users to manipulate the table in some way, there’s a lot of bookkeeping requried to do it right.
Unless you use the view model diffing architecture. Then it becomes simple again.
Read on »
Like interactive articles? Download Playground for this article.
Before Swift 2, there were three main ways of dealing with errors:
- Optionals: for the simplest cases when you don’t care about a reason why an operation failed.
- NSError: used by Cocoa frameworks; upon failure, a method sets an error object to the variable passed as a pointer. This method is undesirable because of its verbosity, and because it’s too easy to ignore errors.
- Result: an enumeration that’s either a
.Success(value) or a
.Failure(error); common pattern among Swift programmers.
(There are also Objective-C exceptions and runtime traps, but those are fatal errors.)
Swift 2 introduces a new error handling model where functions can throw an error, and callers can
catch them. This replaces
NSError in bridged Objective-C classes.
It will also largely replace
Result. The convenient, familiar, compact syntax of Swift 2 errors is simply better than
Result in most cases.
There is an argument to be made, however, that even in Swift 2,
Read on »
Result still has a place. Since it’s a value, you can pass it as an argument (for example, to an async operation handler). You can put it in an array, deal with it lazily, or save in a property. And you can create functions to easily transform, compose and chain those values together.
I wrote this post before watchOS 2, when optimizing traffic to the Watch was essential. Although this is no longer necessary, the approach presented here is still very useful for other reasons, so keep reading!
In this post, I will show you how to dramatically simplify the architecture of your WatchKit application and improve its performance. We will introduce a thin layer between your interface controller and the views (tables, rows, labels, images…). Together with a small set of additions to the WatchKit framework, this will free you from worrying about updating your UI in an efficient manner. Every time your data changes, you will simply tell the framework what you want to display, and the framework will intelligently compute the smallest required set of interface changes for you.
Read on »
Quick WatchKit Pro-Tip™ today.
Text on the Apple Watch can be awkward. You probably saw this when developing or using WatchKit apps: huge gaps left by long words wrapped into a new line, and ugly jagged edges in left-aligned blocks of text. Apple deals with this problem in their own apps by hyphenating text on screen. However,
WKInterfaceLabel doesn’t support hyphenation… Or that seems to be the common knowledge, anyway.
But it’s actually incorrect. WatchKit does support hyphenation, and it’s very easy.
Read on »
In the previous installment of Swifty APIs, we took a look at
NSUserDefaults and gave it a make-over. I pointed out some of its problems, like verbosity and inconsistent behavior, and tried to fix them. The resulting interface was, arguably, cleaner, easier to use, and felt more at home with Swift’s syntax.
Today on my plate is
NSTimer. This class has been a pet peeve of mine for a while. Perhaps I’ve been using it more often than most people (fun fact: one of my apps is essentially a fancy, special-purpose timer), but I really do think that for the simple, almost trivial function it serves, its API seems unnecessarily inconvenient. It feels outdated not just by Swift standards — it stayed unchanged for at least 15 years, despite advancements in Objective-C.
Either way, let’s make it better.
Read on »
Hey, this is an old post, written before Swift 2 came out. I no longer think this is the best approach to JSON deserialization, but it’s still an interesting exploration and you can learn something from it.
Parsing JSON has been a hotly debated topic in the Swift community almost since day one. The staticly typed nature of Swift proved somewhat problematic when facing with this problem. In the world of Swift, the structure and types of data are well-defined and known at compile time. When decoding serialized objects, they’re not. At the same time, the new features of Swift enable different approaches and interesting solutions that simply had not been possible in Objective-C.
Anyway, this is a yet another article exploring different solutions to what seems to be a very mundane problem of dealing with JSON.
Read on »
In Swifty methods, I was arguing that we should resist the temptation to write Swift the way Objective-C used to be written. I argued that we should develop new approaches and conventions to designing interfaces, and that we should, once and for all, abolish Objective-C’s excessive verbosity.
Although it was very well received, the issue I’ve had with the essay is that the arguments I was making were all in the abstract. I gave some examples here and there, but they were low-level, and mostly silly.
And so I decided to start a series of articles called Swifty APIs, where I’m going to take some class or component from an Apple framework and show how I would design it with Swift in mind.
Today, we’ll dissect
Read on »
NSUserDefaults and give it a little make-over. We’re going to make it less verbose, a bit cleaner, and more consistent with other classes. We’ll polish its rough edges and we’ll make use of Swift’s cool features along the way.
If you prefer watching to reading, I also gave a talk on the same topic.
Most programmers learning and writing Swift now are people with existing experience in Objective-C. Many of them have worked with this language, writing iOS and Mac apps, for years. If you’re reading this, there’s a good chance this also describes you. It’s very tempting for us to write Swift the way we’d write Objective-C. It’s all too easy to cram existing habits, conventions and ways of thinking into Swift. But, of course, Swift is a very different language from its predecessor and so it requires new approaches.
Now, there has been a lot of great articles touching on Swift’s cool features like structs, enums, tuples and generics; some people even tried to write functional code in it, but today I want to talk about something more subtle and nuanced: methods.
Even something as trivial as method naming has been a great source of disagreement in the Objective-C community. The language is known for long, verbose names like
tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:. Some people love it, some hate it. There have been good arguments on both sides, but it’s all a moot point — the truth is, that’s the Objective-C convention. And conventions are a good thing — it’s easier to read each other’s code and work together if we all decide on a common coding style.
But Swift, as a brand new language, doesn’t have established conventions yet, so the discussion is open again — and naming aside, there are many great features related to how we define methods that let us write cleaner code than in Objective-C.
So let’s explore the topic.
Read on »