Monday, March 19, 2018

App Reviews - From OK to Great in 12 days

App review prompt

What are the characteristics of a successful app? Is it revenue, number of downloads, app rating, active user count, or your crash-free rating? While each metric plays a role in overall success the important factor is we have the ability to improve the metrics that are most valuable to us. For example, a primary goal for our HealthPartners app this year was to improve our 3.8 app rating. Let's explore the strategy we applied at HealthPartners that improved our app rating to 4.6 in just 12 days. This strategy is actually easier done than said.

Identify the top 3 'Make Good Happen' moments in your app

The most important tip for a successful user review is a timely prompt after the user has finished a simple and valuable workflow. For example, in our HealthPartners app we identified these following workflows as our top 'Make Good Happen' moments:

  1. After a user refills a prescription
  2. After a user schedules a clinic appointment
  3. After a user submits an account reimbursement

After users complete these simple and valuable workflows they will be more likely to submit a positive app review. According to our iTunes Connect metrics 93% of our reviews have been 4 stars or higher.

Trigger app review prompt

Prompting an app review requires minimal code.

if #available(iOS 10.3, *) {

Apple released their rating and review capabilities in iOS 10.3. Therefore, a version check is necessary if you support a prior iOS version. Otherwise the requestReview() trigger is quite simple. However, Apple will only trigger a prompt within your shipped app 3 times a year. Apple's requestReview() algorithm ultimately determines the frequency and timing of the actual prompt.

Limit app review prompt to core users (optional)

Since it's not clear when Apple may display the review prompt I wanted to avoid an app review prompt for first time users. A core user or returning user is more likely to provide positive feedback. Therefore, I limited the review prompt to core users.

App rating trends mashup

Appbot recently published an article comparing app rating trends titled, "Has iOS 11 really affected star ratings?". I performed a mashup and included HealthPartners within their rating diagram to gather a greater perspective of the improvement our app has experienced.

iOS 11 app rating trends

Are these tasks easier done than said? Simply add review prompts to your apps top 3 'Make Good Happen' moments and your ratings will improve dramatically too.

Saturday, May 20, 2017

Adaptive and Self-Sizing Subtitle Cell

fat free ice cream

Imagine eating all the ice cream you ever wanted and not gaining a pound. There's a classic Seinfeld episode about this dream and they eventually learned it was too good to be true. If you've ever used Apple's subtitle cell you may have experienced similar disappointment. The default subtitle cell is adaptive but it does not support self sizing and therefore it is not accessible. If accessibility is a requirement on your projects then the only option is to create a custom Subtitle cell that supports both adaptability and self-sizing.

Adaptive & Self-Sizing Custom Subtitle Cell

An ideal subtitle cell should be both adaptive and self-sizing (see Figure 1). As shown, this custom subtitle cell adapts to support many different configurations. Most importantly, it supports self-sizing - the cell automatically grows to fit the available content and it will grow based on font size adjustments. Now that our cell is also accessible we can certify it fat free!

Adaptive and self-sizing subtitle cell examples
Figure 1. Adaptive and self-sizing subtitle cell examples

Default Subtitle Cell

In comparison, the default subtitle cell when loaded with the exact same content as shown previously is not accessible (see Figure 2). Unfortunately, this option doesn't pass the fat free certification test.

Default subtitle cell examples
Figure 2. Non-accessible Default Subtitle Cell

Custom Subtitle Cell Layout

The auto layout configuration for the custom subtitle cell is very lean (see Figure 3). The Stack Views implicitly manage adaptability and the text labels are configured to support self-sizing.

Subtitle cell layout
Figure 3. Custom Subtitle Cell Layout

Custom Subtitle Cell Configuration

The custom subtitle cell will adapt based on its configured cell data (see Figure 4). This custom subtitle cell and entire demo is available on my GitHub repository.

Subtitle cell data
Figure 4. Subtitle cell data

Sunday, April 2, 2017

Swift Performance Tips for Busy iOS Developers - Presentation

Want to learn quick tips that will improve your apps performance and load time? In this presentation, we’ll explore the latest Swift techniques we can apply to create faster iOS apps. Topics discussed will include:

  • The three dimensions of performance:
    • Allocation (stack vs heap)
    • Reference counting (less vs more)
    • Method dispatch (static vs dynamic)
  • Is Swift faster than Objective-C?
  • Are structs faster than classes?
  • Is inheritance faster than protocol extensions?
  • Grand Central Dispatch patterns
  • Whole module optimization and more

Source Code and Demos

Many of my performance tests are available as Gists. Refer to the slides "Gist" Link in the lower left - Enjoy!

Slide Deck Sneak Peek

Dimensions of performance
Dimensions of performance
Enable Whole Module Optimization
Enable Whole Module Optimization

Avoid for-in
Avoid for-in
Grouping work requests
Grouping work requests

Looking for even more performance tips? The Swift team has an excellent post with even more Swift Performance Tips.

Wednesday, February 8, 2017

Swift Performance Tips for Busy iOS Developers

street outlaw

"It’s time to upgrade". That’s a common theme you’ll hear if you watch Street Outlaws on the Discovery Channel. Their goal is simple - be the fastest car on the street or it’s time to upgrade. They are continuously looking for ways to boost the performance of their cars (nitrous, turbos, fiberglass panels, etc). Some performance mods are quick and others take time to implement and refine. In this post, let's focus on Swift performance improvements we can implement and release rather quickly. In fact, most of these improvements should only cost a story point or two:

Mark classes final

A final class will explicitly enable static dispatch for all methods which allows the compiler to optimize methods at compile time resulting in more efficient method invocation at runtime. There are two types of method dispatch: static and dynamic. Dynamic dispatch (the default type of method dispatch) is not as efficient because its dispatch isn’t known until runtime. Dynamic dispatch provides runtime conveniences like polymorphism, inheritance, and overloading but incurs a higher performance penalty. Therefore, by simply marking classes final we get a minor performance boost rather quickly. Refer to Apple’s Understanding Swift Performance talk for additional details.

Prefer isEmpty over count > 0

The native isEmpty method is more efficient because it only verifies one element exists where as the count property iterates the entire collection. Want to enforce this efficient practice within your codebase? SwiftLint has a static analysis check for this rule.

Convert strings to enums

In Apple’s Understanding Swift Performance talk they mentioned three dimensions of performance (see Listing 1).

Listing 1. Dimensions of Performance
LessReference CountingMore
StaticMethod DispatchDynamic

When creating Swift objects it’s important to understand how much an object or property weighs in regards to these three dimensions. For example, a String is not an efficient type because it is allocated on the heap and it incurs a reference count. Comparatively, Enums are much more efficient because they are allocated on the stack, do not incur a reference count, and as a bonus they are type safe resulting in a win-win-win. Interested in automatically converting your localizable strings, asset names, or storyboard names to enums? SwiftGen has accomplished this task nicely on my projects.

Import existing images from the file navigator into an asset catalog

An asset catalog is preferred because it caches images, optimizes memory consumption, and enables lightweight App Store downloads via App Thinning - unnecessary image densities are not downloaded. Xcode has a wizard for automatically importing images into an asset catalog rather quickly. Refer to Apple’s Improving Existing Apps with Modern Best Practices talk for additional details.

Parse JSON on a background thread

This allows the main thread to remain idle to serve other threads while the JSON is transformed to an object. Refer to Apple’s Concurrent Programming with GCD in Swift 3 talk for more details.

let json = [String : Any]()   
  let dataTrasformQueue = DispatchQueue(label: “”)   
  dataTrasformQueue.async {   
   let result = T(json: json) // Transform JSON to object on background thread   
   DispatchQueue.main.async {   
    completionHandler(result) // Return control to main thread after object is parsed   

Prefer structs over classes (until you reach their point of diminishing returns)

Structs have many advantages over classes: they are allocated on the stack, they prevent unintended sharing, their memberwise initializer is a nice convenience, and a struct by itself doesn't incur reference counting. However, a structs properties will incur reference counting when they are reference types like String. Therefore, structs have a point of diminishing returns in regards to reference counting that multiplies proportionally by their number of properties which are reference types. A struct containing more than 2 reference types begins to incur a higher reference count than a comparative class. Refer to Apple’s Understanding Swift Performance talk for additional details.

Rewrite Objective-C objects in Swift

Refactoring Objective-C objects to Swift was the primary theme in Apple’s Optimizing App Startup Time talk. This tip barely makes the list for “busy developers” because the scope of this task may be large depending on your codebase but it’ll become more manageable by focusing on converting one Objective-C class per week or iteration.


The fastest car doesn't always win. The quickest car from start to finish does. A driver and the adjustments they make to their car has a huge impact on their performance. The tips above are quick adjustments we can make to our Swift code so our apps will be more efficient from point A to point B.