• Stars
    star
    480
  • Rank 89,502 (Top 2 %)
  • Language
  • Created about 12 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Best Practices for iOS Software Design.

Best Practices for iOS Software Design

This article's goal is to help you write stable code for your iOS applications. I highly encourage you to contribute your own best practices via Github's pull requests.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.

Originally written by: Jeff Verkoeyen (@featherless)

Table of Contents

Be Mindful of the Lifetime of Views

Remind yourself constantly that, at any time, your views may be destroyed.

Do not access self.view in init- methods

You should never access self.view in your controller's initialization methods. Doing so almost always leads to hard to debug bugs because that initialization logic will not be executed again after a memory warning.

Consider a simple example:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
  if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
    self.view.backgroundColor = [UIColor underPageBackgroundColor];
  }
  return self;
}

Imagine this controller is the root of a navigation stack and a memory warning occurs. When we pop back to this controller, the view will no longer have underPageBackgroundColor as its background color. This leads to debugging frustration, even for experienced iOS engineers.

Use data source protocols to strongly separate data from views

When designing views that interact with data sets, always fetch the data via a data source protocol rather than exposing setters. Views are not data containers and should not be designed to enable any such abuse. Rather, views should be treated as expendable components that may leave existence at any point in time.

As a general rule of thumb, anything beyond static presentation information in a view should be requested via a data source or delegate.

UILabel is a good example of a view that does not need a data source. All of its properties are set once and are generally not expected to change throughout the lifetime of the view.

UITableView on the other hand requires a data source to fetch its data. Let's imagine what using UITableView would be like if it didn't have a data source and instead only provided setters.

This design will lead to inevitable abuse when developers attempt to use the table view object as a place to store their data. When the table view is inevitably released due to a memory warning the data will also be lost! This means that we need to store the data elsewhere anyway in order to guarantee its lifetime across multiple instances of the table view.

UIViewController

View controllers are the binding between your models and your views.

Use the existing navigation item object

Every instance of a UIViewController has a navigationItem property which should be used to specify the left and right navigation buttons and the title view. You should not create a UINavigationItem object because the base UIViewController implementation will automatically create one when you access self.navigationItem. Simply access self.navigationItem and set its properties accordingly.

// UIViewController will automatically create the navigationItem object.
self.navigationItem.rightBarButtonItem = doneButton;

NSObject

Only expose public properties and methods in headers

Objective-c allows you to define private properties in a category interface within your .m files; take advantage of this fact to provide better headers.

This is equivalent to defining ivars as @private with the added benefit of changes not causing build propagation when modifications are made to the internal structure of an object. This can be particularly helpful if an object is being refactored in a fairly large project.

Example

ViewController.h

@interface ViewController : UIViewController
@property (nonatomic, readonly, assign) NSInteger objectId;
@end

ViewController.m

#import "ViewController.h"

@interface ViewController()
@property (nonatomic, readwrite, assign) NSInteger objectId;
// Notice that this property doesn't need to be in the .h. Objective-C will create this
// property on the fly!
@property (nonatomic, readwrite, retain) UILabel* objectLabel;
@end

@implementation ViewController
@synthesize objectId;
@synthesize objectLabel;

...

@end

Debugging

Use lldb for debugging

lldb allows you to inspect properties on classes that don't have explicit ivars declared in the object's interface.

To use lldb, select "Edit Scheme..." from the "Product" menu (or press Cmd+Shift+<). Select the "Run" tab on the left-hand side of the scheme editor. Change the debugger drop down to "LLDB".

Use NSZombieEnabled to find object leaks

When NSZombieEnabled is enabled, objects that are released from memory will be kept around as "zombies". If you attempt to access the released object again in the future, rather than crashing with very little context, you will be shown the name of the object that was being accessed. This can be incredibly helpful in determining where memory leaks are occurring.

To turn on NSZombieEnabled, select "Edit Scheme..." from the "Product" menu (or press Cmd+Shift+<). Select the "Run" tab on the left-hand side of the scheme editor. Select the "Arguments" tab in that page. Add a new Environment Variable and call it NSZombieEnabled. Set its value to YES.

Documentation

Data Source Protocols

For required methods, start the preamble with "Tells the data source" and end it with "(required)". For example:

Tells the data source to return the number of rows in a given section of a table view. (required)

For optional methods, start the documentation with "Asks the data source". For example:

Asks the data source to return the number of pages in the launcher view.

Delegate Protocols

For methods that simply notify the delegate that an action has occurred, start the preamble with "Informs the delegate". For example:

Informs the delegate that the specified item on the specified page has been selected.

More Repositories

1

nimbus

The iOS framework that grows only as fast as its documentation
Objective-C
6,449
star
2

iOS-Framework

How to create, develop, and distribute iOS Static Frameworks quickly and efficiently
Shell
2,621
star
3

ObjQREncoder

Objective-C QR Encoder
Objective-C
389
star
4

BinaryCodable

Swift Codable-like interfaces for binary representations.
Swift
385
star
5

liteqr

Lite QR Reader in Objective C ported from zxing
C++
113
star
6

windfish

A tracing disassembler & UI for Gameboy ROMs โ€” integrated with Sameboy for emulation & debugging.
Assembly
69
star
7

swift-midi

MIDI in Swift
Swift
21
star
8

jekyll-dayone

A Day One Jekyll plugin for associating Day One entries with Jekyll posts.
Ruby
20
star
9

Three20-Tutorials

Objective-C
16
star
10

uwdata.ca

The University of Waterloo's Public Data API
PHP
13
star
11

ElectricSidecar

An unofficial companion app for the Porsche Taycan
Swift
10
star
12

OAuthConsumerTouch

OAuthConsumer for the iPhone lineup
Objective-C
9
star
13

BreezeJSEngine

A javascript engine for building games with HTML5 canvas tags.
JavaScript
9
star
14

12tweet

tiny little robots that live in the twittersphere
Python
7
star
15

extXML

Three20 XML Extension for parsing XML objects into Objective-C NSObjects.
Objective-C
5
star
16

extCSSStyle

This extension provides support for reading Three20 style sheets from CSS files.
Objective-C
4
star
17

FigmaKit

A Swift package for working with the Figma API.
Swift
4
star
18

snaapilookup

Snappy API lookups for software developers.
PHP
4
star
19

MySqlClient

A pure Swift MySQL client with Codable query support.
Swift
4
star
20

profiles

Jeff's profiles
Shell
3
star
21

Lighthouse-Keeper-for-Things

A synchronization script from Lighthouse to Things for Mac
Python
3
star
22

playgrounds

Playground versions of featherless software design articles.
Swift
3
star
23

Daydreamer

A Figma viewer created in Swift Playgrounds for iPad
Swift
3
star
24

JVPortfolio

Jeff Verkoeyen's Portfolio
PHP
3
star
25

findpassion

Find's passionate people.
Python
2
star
26

Github-Issues-2.1

Giving some love to Pull Requests
JavaScript
2
star
27

Snaapi

Snaapi API reference.
JavaScript
2
star
28

StormChaser

A large-scale media organization & auditioning app for Apple platforms.
Swift
2
star
29

Nimbus-Speedrun-Settings

Nimbus Speedrun of the Settings iOS app
Objective-C
2
star
30

Three20-Scope

Three20's community.
PHP
1
star
31

macbookproless

Swift
1
star
32

nimbus-models

This is a WIP
Swift
1
star