Over the last seven years, our team at Originate has created countless iOS apps. Along the way we have continuously fine-tuned our iOS development process, creating best practices that we apply to every new app we build.
We’ve put some of this down on paper in the form of two checklists, one used when starting an iOS project, and one used when preparing to submit to the App Store.
Following these checklists has helped our team work together more efficiently, architect better solutions, reduce development time, and reduce the risks that come with publishing an app to the App Store.
We hope these checklists will do the same for you.
Starting an iOS project
a. Start by creating a new repo in GitHub and adding the appropriate iOS gitignore file.
b. Be sure to follow the git-flow workflow, with master holding your App Store builds, dev your latest development code, and feature branches holding the current work in progress.
a. Make sure everyone in the team is on the same version of Xcode.
b. Turn on “Analyze during build” and “Treat Warnings as Errors” (Set it under “Build Settings” in your application target).
c. Turn off tabs and use spaces: XCode > Preferences > Text Editing > Indentation > Prefer Indent using Spaces, Tab width 2, Indent width 2.
Jenkins/OS X Server/TestFlight
Setup CI/CD (Continuous Integration/Continuous Deployment) making sure with every push to dev all tests are run and an Ad Hoc build is created/emailed to the team (with the commit logs in the email body). If the build or tests failed, a failure email should instead be sent out to the team. At Originate most of our iOS projects use OS X Server integrated with TestFlight.
a. Follow Apple's recommended iOS coding style guide.
b. In addition, follow recommendations here: http://qualitycoding.org/preprocessor/
c. Keep your .h files short and simple, exposing only what is needed by other classes. Move all other methods, properties, instance variables declarations, etc. inside the .m file.
d. Name your view controllers based on the page they are displaying (e.g.
e. Organize your project navigator and files using groups. Good group names are Data Models, Views, Controllers, App Delegate, Supporting Files, Tools, etc. Messy project navigators should not be accepted.
e. Before submitting a pull request, go over the checklist at the bottom of our effective code review blog post and look for red flags.
a. MVC (Model View Controller) is sometimes jokingly called Massive View Controller in iOS development. These massive controllers that do everything are common mistakes for beginners. They are not acceptable. As needed, split out table related delegates/data sources from the view controller into their own separate classes. Split out views (especially if they are reused) into their own view classes. Make sure helper methods are pushed out into helper classes. In addition, the View Controller should not make any calls to the server, instead the Model or a manager class should handle this.
a. Be sure to use constraints/autolayout for your views and support different screen sizes. Otherwise you will have to manually configure the frame sizes/positions for each view to make sure it fits correctly for each screen size. PureLayout and FLKAutoLayout have been used on some projects at Originate.
b. Determine if Nib files will be used. Originate recommends avoiding them, but leaves the decision to the Tech Lead. Storyboards are not used as they they are hard to manage with multiple developers (e.g. trying to merge a storyboard), slow down Xcode, and add a level of complexity to the code that is not necessary.
c. Use FrameAccessor to modify frames if needed. This will make it very easy to get and set a
UIView’s size and origin.
Fonts and Colors
Standardizing fonts and colors throughout the app (i.e. create helper classes) so that it's easy to maintain/modify them as needed. This also makes for cleaner code that doesn’t have random RGB or font strings scattered in the views.
a. All strings displayed to the user must be placed in a localization file.
b. Avoid using image assets that contain text, use a
UILabelinstead, pulling the text out of the localization file.
http://replay.io is our go-to platform for analytics at Originate.
Although Apple and iTunes Connect are making progress here, it’s still best to use a third-party tool like Crashlytics. They work much faster and have a better UI/reporting interface.
Add AOP support if needed (e.g. for logging).
Third party code dependencies
Cocoapods can be used to maintain third-party dependencies. At Originate this decision is left to the Tech Lead.
a. Add the ability to toggle between server environments (e.g. QA, dev, staging, etc.) in app settings.
b. If needed, implement an app update notification system, where the server can inform the app a newer version is available and the app can display the appropriate message to the user.
c. Make sure an activity indicator is displayed during server calls. MRProgress has been used on some projects at Originate.
e. For debugging, make sure all server communications (i.e. web service requests/responses) are printed out to the console.
NOTE: Use DLog to log all requests and response (in debug mode) to the console:
#ifdef DEBUG #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #else #define DLog(...); #endif
Small tweaks to an app can go a long way. Make sure to include simple user expected features like pull-to-refresh, tap status bar for scroll to top, activity indicator during server calls, etc. to make the app user friendly. Your Design and Product team should be on top of this already. The iOS Human Interface Guidelines is a good reference doc for them.
Lastly, ensure that the process to create the needed accounts (e.g. iTunes Connect, Urban Airship, Analytics Accounts, etc.) is started.
Submitting to the App Store
Releasing to the App Store must not be taken lightly. Steps must be taken to ensure the submitted app follows Apple’s guidelines and will work once published to the store. Four to eight hours should be allocated to perform this task.
When your app has been tested and is ready to release, follow these steps:
a. At a high level, Apple goes over everything related to App testing, Ad Hoc distribution, and App Store release in the App Distribution Guide. This document should be reviewed.
NOTE: Although not listed in the rejections link above, we’ve found that often developers forget to add content flagging for apps that create user generated data. Apple rejects these apps until content flagging is added.
If you are submitting an updated app that uses Core Data, then you must make sure to write a migration script in order to properly propagate changes to the DB. If this is not done, then it's possible that the app can crash once updated and the user will have to delete and reinstall the app. See Core Data Model Versioning and Data Migration.
App Review Screen
When you want your app to be reviewed by the user, UAAppReviewManager makes sure the review is done at the right time.
In the “Edit Scheme” section of Xcode, “Archive” should be set to “Release”. Release builds must hide log statements and turn off any test code/test screens used for development.
NOTE: Due to compiler optimizations, release builds can sometimes function differently than debug builds. It is best to start testing release builds a few days before the release to the App Store in order to capture any possible issues.
Point your release build at the proper production servers (and use HTTPS)
Release Candidate Ad Hoc builds / App Store build
Make sure to use the correct Bundle Identifier, Apple ID, certificates (e.g. Push Certificates), etc. for the release candidate and App Store builds.
Test Release Candidate configuration
a. Make sure the app is communicating with the correct production servers (using HTTPS).
b. Make sure all test screens are hidden.
c. Make sure no sensitive data is printed to the console.
d. Make sure Analytics is working with the correct production account.
e. Make sure services such as Urban Airship are working with the correct production account.
Push to master
a. Update the bundle version number in the app plist file. This number does not have to match the version number you assign to the app on the App Store, but it's best that it does.
b. Push the code that is ready for release to the master branch and tag it.
Setup the app in iTunes Connect
a. In iTunes Connect create a new App, or if this is an update, select "Add Version".
b. Make sure to fill in all data and upload all necessary images (and video).
NOTE: Only the fields "Description" and "What's New In This Version" can be modified once the app is accepted and placed in the store. Other important fields like images cannot be modified.
Use Xcode to create the App Store build and upload to iTunes Connect.