The year 2015 is over and 2016 has already started with new projects and new ideas. It's high time to look back now and revise all the good solutions, that helped us in 2015. This summary will not be short, as there are quite a lot of iOS development tools and practices, that were really useful in app development.

Fastlane

At the beginning of every iOS project, we set up Continuous Integration and Deployment. It includes several tasks, such as installing dependencies, running tests, packaging an application, and submitting it to iTunes/Testflight. This process could be much more complicated if we were not using Fastlane.tools. They are seriously amazing. The following are the most common pieces of our setup in Fastfile:

before_all do
cocoapods
scan
end
# Increment build number to current date
lane :set_build_number do
increment_build_number(
build_number: Time.new.strftime("%Y.%m.%d.%H%M")
)
end
lane :beta do |beta|
match
set_build_number
configuration = beta[:configuration] || "Release"
gym(configuration: configuration)
pilot(skip_submission: true)
end
view raw Fastfile hosted with ❤ by GitHub

In just 20 lines of code we:

  • Install dependencies
  • Run tests
  • Fetch certificates and provisioning profiles from the internal repo, automatically managed by match
  • Generate and set the build number from the current time
  • Package .ipa file using gym
  • Upload .ipa to TestFlight

And what's even more impressive, is that all these tools are intelligently linked together to work seamlessly. So if you need to generate screenshots for your app, or update a changelog, or wait while a build is processing, you'll be working with the same tools, because Fastlane just seems to cover all possible aspects of continuous deployment you could think of. We seriously can't wait for the next tool that Felix Krause will hopefully develop.

IBInspectable

Having well-written code in an app is nice. But do you know what's nicer? Not having to write code at all. IBInspectable is an incredibly cool feature of Interface Builder, that allows us to write significantly less code than before. For example, sometimes we need to make a button with borders and cornered layers. Sometimes we may need a rounded image. Having just a single extension on UIView we are able to achieve that without subclassing anything:

extension UIView {
@IBInspectable var cornerRadius: CGFloat {
get { return layer.cornerRadius }
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
@IBInspectable var borderWidth: CGFloat {
get { return layer.borderWidth }
set { layer.borderWidth = newValue }
}
@IBInspectable var borderColor : UIColor {
get { return UIColor(CGColor: layer.borderColor ?? UIColor.whiteColor().CGColor }
set { layer.borderColor = newValue.CGColor }
}
}

This extension works for all UIView subclasses, not just UIButton or UIImageView. You won't see those changes in a xib or a storyboard, because we're not using IBDesignable here. However, completely dropping the subclassing requirement seems good enough. Less code = win.

Views Loadable from XIB

This is not something new, but somehow we stumbled upon this solution only in 2015. And it completely blew us away. The task is simple - we have a storyboard, that contains a view, that we want to design in a separate XIB, and then just drop a UIView on our storyboard, set its class, and have it automatically loaded from another XIB file. Wouldn't that be cool? It turns out it's actually a simple thing to do, here's our tip:

protocol NibDefinable {
var nibName: String { get }
}
extension NibDefinable {
var nibName : String {
return String(self.dynamicType)
}
}
class LoadableFromXibView: UIView, NibDefinable {
@IBOutlet weak var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
view = loadViewFromXib()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
backgroundColor = .clearColor()
addSubview(view)
}
private func loadViewFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil).first as! UIView
return view
}
}

Setup for these kinds of views is straightforward:

  1. Create LoadableFromXibView subclass
  2. Create a xib file, set the File's owner as your subclass
  3. Drag outlets and design your view as usual

These views can be created from code, loaded to a storyboard and a xib in any way you want. All you need is to set a class for UIView in your storyboard.

Although everything sounds simple, it turns out that this approach saves us an incredible amount of time, and provides our views with wonderful reusability. It is sometimes common to design UITableViewCells and UICollectionViewCells as a composition of loadable views, that can be reused elsewhere.

Swift

Swift is controversial. When it was released in June 2014 in beta, it was very unstable. In fact, it was still unstable one year later, when Apple announced Swift 2. And really, it is still unstable now, constantly crashing code highlighting, compiler, and even XCode. However, Swift 2.1 is much more stable than Swift 1.2. So, we hope that we'll be working in a stable IDE once again in Spring 2016 when Swift 2.2 is released with all these awesome fixes.

But even now code in Swift is much shorter than in Objective-C. It provides us with an ability to work with types directly, using Generics. It has awesome features like associated types, protocol extensions, and default implementations. While Swift lacks in runtime a bit, it still completely beats Objective-C in compile-time knowledge about variables, types, and expressions.

Optionals can be a source of frustration for developers, moving from Objective-C. However, once you let them sink in, you start to realize, why it's always needed to understand when a variable can be nil or when it never can become nil.

It's also much easier to declare protocols in Swift. It was simple in Objective-C as well, but there was rarely an idea to use protocols as traits or mixins there as in Ruby, for example. Protocol-oriented programming is a powerful concept, that can change the way you code forever.

We bet big on Swift. 2015 was the last year we considered Objective-C as a language choice for a project. In 2016 we are moving to "Swift by default". Thank you, Apple!

Stack Views

If protocol-oriented programming can change the way you write code, stack views can change the way you design interfaces on iOS. If you have the luxury of supporting iOS 9 only, go ahead and use UIStackViews. We still support iOS 8, so we needed to find a compatible solution, which was to go with TZStackView.

There are a lot of use cases for stack views, but the most common ones for us were building forms (e.g. sign up) and single content interfaces. For example, we may have a profile for a current user, and a profile for another user. They consist of several common views, that we want to reuse. However, in some places they are different, so we need to be able to compose them differently. And here's where loadable views and stack views really help. This is, for example, how current user profile views are created:

let stacks = [UserProfileStatsView(), SwitchCompanyView(), SendInvitationToCompanyView(), LogoutButtonView()]
stackView.axis = .Vertical
stacks.forEach {
stackView.addArrangedSubview($0)
}

Of course, there's some more setup involved in how we bind data to these views, but notice how easily the interface is constructed. We don't have to worry about constraints amongst these views, because the stack view manages all of them automatically. We gain reusability and flexibility. If we need to add or remove some views from a view controller, it's simply about removing a stack from the stack view. We don't have to go and undo all constraints from a view controller and create them from scratch.

One thing to remember, though, is that Stack View is not a replacement for UITableView or UICollectionView. If you have a lot of repetitive views horizontally or vertically, it's much easier to use UITableView or UICollectionView. The stack view really rocks only if you have an interface with several different views.

Tools

While architectural and design solutions are great, you really need the best tools available to be able to do your work efficiently. And here's our list of best iOS development tools we used in 2015:

Alamofire + AlamofireImage

AFNetworking was a long time king for networking on iOS. However, it became bloated and was buried under hundreds of issues. It was not really nice to Swift’s type system as well, so we started to look for a replacement. And we found that Alamofire and AlamofireImage are really a good answer to all our questions. These frameworks are the best stuff that existed in AFNetworking, completely rebuilt and rethought to bring Swifty experience to networking. Maintained by Alamofire Software Foundation, they have great test coverage, incredible tech support, and a very low amount of open issues. Alamofire allows powerful usage of Swift generics, which helps to build a type-safe response and error parsing.

Moving AlamofireImage to a separate repository was a very good decision. It contains very well-structured code with an incredible amount of features AFNetworking extensions could only dream of. These are single and multi-pass image filters, auto purging cache, image transitions, download queues and much more.

SwiftyJSON

Let's face it. Everyone is writing his/her own JSON parser in Swift. And while some of them are interesting, like Argo, most of the others are just a mess with operator overloads, that really do not solve any problem. However, SwiftyJSON does. It is really the best and the safest way to work with JSON in Swift, and there's really almost no reason to search for something else.

FuzzyAutocomplete

Writing code is what we do every day. And to do it quickly, you really need tools to boost your coding productivity. FuzzyAutocomplete plugin for XCode is one of them. It should really be preinstalled with XCode.

CocoaPods

2016 will be a year of competing package managers on iOS. CocoaPods, Carthage, Swift Package Manager - we don't know which one will be more robust and commonly-used, but 2015 was really a year of CocoaPods. This incredible package manager allows installing dependencies in just one line of code. And support for dynamic frameworks is great if you work with Swift.

2016

2015 was an interesting year for iOS development. We'll remember our sadness every time when DerivedData messed our build. We'll remember the happiness of looking at beautifully organized generic Swift code, that we continue to reuse in every project we write. And most importantly, we do always remember the joy when some new technology or approach changes our code style forever. We hope that the list of top iOS development practices and tools will be longer next time we decide to make it up.

Stay hungry. Stay foolish. Good luck to all of you in 2016!

Looking for a professional team of iOS developers?

At MLSDev, we have talented and skilled iOS developers who are ready to deal with the most challenging tasks and create great apps fot iOS. Contact us to discuss your project.

Get in touch