SlideShare a Scribd company logo
1 of 42
Download to read offline
iOS bad Best
Practices
Do not scold the code - make it better
Setup the coding style
Oops… I missed something again
Objective-C Style Guide
Dot Notation Syntax
Dot notation is RECOMMENDED over bracket notation for getting and setting properties.

For example:

view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
Not:

[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
Spacing
Method braces and other braces (if/else/switch/while etc.) MUST open on the same line as the statement. Braces MUST close on a new line.

For example:

if (user.isHappy) {
// Do something
} else {
// Do something else
}
Not:
if (user.isHappy)
{
// Do something
}
else
{
// Do something else
}
Conditionals
For example:

if (!error) {
return success;
}
Not:

if (!error)
return success;
or

if (!error) return success;
Objective-C Style Guide
Ternary Operator
The intent of the ternary operator, ? , is to increase clarity or code neatness. The ternary SHOULD only evaluate a single condition per
expression. Evaluating multiple conditions is usually more understandable as an if statement or refactored into named variables.

For example:

result = a > b ? x : y;
Not:

result = a > b ? x = c > d ? c : d : y;
Methods
In method signatures, there SHOULD be a space after the scope (- or + symbol). There SHOULD be a space between the method segments.

For example:

- (void)setExampleText:(NSString *)text image:(UIImage *)image;
Not:
+(void)openSignInVC;
Variables
Variables SHOULD be named descriptively, with the variable’s name clearly communicating what the variable is and pertinent information a
programmer needs to use that value properly.

For example:

• NSString *title: It is reasonable to assume a “title” is a string.

• NSString *titleHTML: This indicates a title that may contain HTML which needs parsing for display. “HTML” is needed for a
programmer to use this variable effectively.
Asterisks indicating a type is a pointer MUST be “attached to” the variable name. For example, NSString *text not NSString* text or
NSString * text, except in the case of constants (NSString * const NYTConstantString).

Variable Qualifiers
When it comes to the variable qualifiers introduced with ARC, the qualifier (__strong, __weak, __unsafe_unretained, __autoreleasing)
SHOULD be placed between the asterisks and the variable name, e.g., NSString * __weak text.
Objective-C Style Guide
Naming
Apple naming conventions SHOULD be adhered to wherever possible, especially those related to memory management rules (NARC).

Long, descriptive method and variable names are good.

For example:

UIButton *settingsButton;
Not

UIButton *setBut;
For example:

static const NSTimeInterval NYTArticleViewControllerNavigationFadeAnimationDuration = 0.3;
Not:

static const NSTimeInterval fadetime = 1.7;
Categories
Categories are RECOMMENDED to concisely segment functionality and should be named to describe that functionality.

For example:

@interface UIViewController (NYTMediaPlaying)
@interface NSString (NSStringEncodingDetection)
Not:

@interface NYTAdvertisement (private)
@interface NSString (NYTAdditions)
Methods and properties added in categories MUST be named with an app- or organization-specific prefix. This avoids unintentionally overriding an
existing method, and it reduces the chance of two categories from different libraries adding a method of the same name. (The Objective-C runtime
doesn’t specify which method will be called in the latter case, which can lead to unintended effects.)

For example:

@interface NSArray (NYTAccessors)
- (id)nyt_objectOrNilAtIndex:(NSUInteger)index;
@end
Not:

@interface NSArray (NYTAccessors)
- (id)objectOrNilAtIndex:(NSUInteger)index;
@end
Objective-C Style Guide
Comments
When they are needed, comments SHOULD be used to explain why a particular piece of code does something. Any comments that are used MUST be kept up-to-date
or deleted.

No comment
Not:
// Start monitoring network connection
[Reachability defaultReachability];
Literals
NSString, NSDictionary, NSArray, and NSNumber literals SHOULD be used whenever creating immutable instances of those objects. Pay special care that nil values not
be passed into NSArray and NSDictionary literals, as this will cause a crash.

For example:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
Not:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];
Constants
Constants are RECOMMENDED over in-line string literals or numbers, as they allow for easy reproduction of commonly used variables and can be quickly changed
without the need for find and replace. Constants MUST be declared as static constants. Constants MAY be declared as #define when explicitly being used as a
macro.

For example:

static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat NYTImageThumbnailHeight = 50.0;
Not:

#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling
Objective-C Style Guide
Booleans
Values MUST NOT be compared directly to YES, because YES is defined as 1, and a BOOL in Objective-C is a CHAR type that is 8 bits long
(so a value of 11111110 will return NO if compared to YES).

For a BOOL value:

if (isAwesome)
if (!someNumber.boolValue)
if (someNumber.boolValue == NO)
Not:

if (isAwesome == YES) // Never do this.
Imports
If there is more than one import statement, statements MUST be grouped together. Groups MAY be commented.

// Frameworks
@import QuartzCore;
// Models
#import "NYTUser.h"
// Views
#import "NYTButton.h"
#import “NYTUserView.h"
https://github.com/NYTimes/objective-c-style-guide
Setup the coding style
How it appears in Swift
Swift Style Guide
Spacing
Preferred:

if user.isHappy {
// Do something
} else {
// Do something else
}
Not Preferred:

if user.isHappy
{
// Do something
}
else {
// Do something else
}
	 •	 There should be exactly one blank line between methods to aid in visual clarity and organization. Whitespace within methods should separate
functionality, but having too many sections in a method often means you should refactor into several methods.

override func viewDidLoad() {
super.viewDidLoad()
setup()
validate()
}
	 •	 Colons always have no space on the left and one space on the right. Exceptions are the ternary operator ? :, empty dictionary [:] and #selector
syntax for unnamed parameters (_:).

Preferred:

class TestDatabase: Database {
var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}
Not Preferred:

class TestDatabase : Database {
var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}
Swift Style Guide
Comments
When they are needed, use comments to explain why a particular piece of code does something. Comments must be kept up-to-date or
deleted.

Avoid block comments inline with code, as the code should be as self-documenting as possible. Exception: This does not apply to those
comments used to generate documentation.
Delegates
When creating custom delegate methods, an unnamed first parameter should be the delegate source. (UIKit contains numerous examples
of this.)
Preferred:

func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
Not Preferred:

func didSelectName(namePicker: NamePickerViewController, name: String)
func namePickerShouldReload() -> Bool
Use Type Inferred Context
Use compiler inferred context to write shorter, clear code. (Also see Type Inference.)

Preferred:

let selector = #selector(viewDidLoad)
view.backgroundColor = .red
let toView = context.view(forKey: .to)
let view = UIView(frame: .zero)
Not Preferred:

let selector = #selector(ViewController.viewDidLoad)
view.backgroundColor = UIColor.red
let toView = context.view(forKey: UITransitionContextViewKey.to)
let view = UIView(frame: CGRect.zero)
Swift Style Guide
Code Organization
Use extensions to organize your code into logical blocks of functionality. Each extension should be set off with a // MARK: - comment to
keep things well-organized.

Protocol Conformance
In particular, when adding protocol conformance to a model, prefer adding a separate extension for the protocol methods. This keeps the
related methods grouped together with the protocol and can simplify instructions to add a protocol to a class with its associated
methods.

Preferred:

class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
Not Preferred:

class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
Swift Style Guide
Unused Code
Unused (dead) code, including Xcode template code and placeholder comments should be removed. An exception is when your tutorial
or book instructs the user to use the commented code.

Aspirational methods not directly associated with the tutorial whose implementation simply calls the superclass should also be removed.
This includes any empty/unused UIApplicationDelegate methods.

Preferred:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Database.contacts.count
}
Not Preferred:

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return Database.contacts.count
}
Minimal Imports
Keep imports minimal. For example, don't import UIKit when importing Foundation will suffice.
Swift Style Guide
Classes and Structures
Remember, structs have value semantics. 

Classes have reference semantics.

NOTE
Structures are always copied when they are passed around in your code, and do not use reference counting.
NOTE
However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying
to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization.
Use of Self
For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods.

Use self only when required by the compiler (in @escaping closures, or in initializers to disambiguate properties from arguments). In other
words, if it compiles without self then omit it.

Computed Properties
For conciseness, if a computed property is read-only, omit the get clause. The get clause is required only when a set clause is provided.

Preferred:

var diameter: Double {
return radius * 2
}
Not Preferred:

var diameter: Double {
get {
return radius * 2
}
}
Swift Style Guide
Final
Marking classes or members as final in tutorials can distract from the main topic and is not required. Nevertheless, use of final can sometimes clarify your intent and is worth the
cost. In the below example, Box has a particular purpose and customization in a derived class is not intended. Marking it final makes that clear.

// Turn any generic type into a reference type using this Box class.
final class Box<T> {
let value: T
init(_ value: T) {
self.value = value
}
}
Function Declarations
Keep short function declarations on one line including the opening brace:

func reticulateSplines(spline: [Double]) -> Bool {
// reticulate code goes here
}
For functions with long signatures, add line breaks at appropriate points and add an extra indent on subsequent lines:

func reticulateSplines(spline: [Double], adjustmentFactor: Double,
translateConstant: Int, comment: String) -> Bool {
// reticulate code goes here
}
Closure Expressions
Use trailing closure syntax only if there's a single closure expression parameter at the end of the argument list. Give the closure parameters descriptive names.

Preferred:

UIView.animate(withDuration: 1.0) {
self.myView.alpha = 0
}
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}, completion: { finished in
self.myView.removeFromSuperview()
})
Not Preferred:

UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
})
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}) { f in
self.myView.removeFromSuperview()
}
Swift Style Guide
Constants
Type properties declared in this way are generally preferred over global constants because they are easier to distinguish from instance
properties. Example:

Preferred:

enum Math {
static let e = 2.718281828459045235360287
static let root2 = 1.41421356237309504880168872
}
let hypotenuse = side * Math.root2
Optionals
Preferred:

var subview: UIView?
var volume: Double?
// later on...
if let subview = subview, let volume = volume {
// do something with unwrapped subview and volume
}
Not Preferred:

var optionalSubview: UIView?
var volume: Double?
if let unwrappedSubview = optionalSubview {
if let realVolume = volume {
// do something with unwrappedSubview and realVolume
}
}
Swift Style Guide
Lazy Initialization
Consider using lazy initialization for finer grain control over object lifetime. This is especially true for UIViewController that loads views lazily. You can either use a
closure that is immediately called { }() or call a private factory method. Example:

lazy var locationManager: CLLocationManager = self.makeLocationManager()
private func makeLocationManager() -> CLLocationManager {
let manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestAlwaysAuthorization()
return manager
}
Type Inference
Prefer compact code and let the compiler infer the type for constants or variables of single instances. Type inference is also appropriate for small (non-empty) arrays
and dictionaries. When required, specify the specific type such as CGFloat or Int16.

Preferred:

let message = "Click the button"
let currentBounds = computeViewBounds()
var names = ["Mic", "Sam", "Christine"]
let maximumWidth: CGFloat = 106.5
Not Preferred:

let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
let names = [String]()
Syntactic Sugar
Prefer the shortcut versions of type declarations over the full generics syntax.

Preferred:

var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
Not Preferred:

var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
Swift Style Guide
Memory Management
Code (even non-production, tutorial demo code) should not create reference cycles. Analyze your object graph and prevent strong cycles
with weak and unowned references. Alternatively, use value types (struct, enum) to prevent cycles altogether.

Extending object lifetime
Extend object lifetime using the [weak self] and guard let strongSelf = self else { return } idiom. [weak self] is preferred to
[unowned self] where it is not immediately obvious that self outlives the closure. Explicitly extending lifetime is preferred to optional
unwrapping.

Preferred

resource.request().onComplete { [weak self] response in
guard let strongSelf = self else {
return
}
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
Not Preferred

// might crash if self is released before response returns
resource.request().onComplete { [unowned self] response in
let model = self.updateModel(response)
self.updateUI(model)
}
Not Preferred

// deallocate could happen between updating the model and updating UI
resource.request().onComplete { [weak self] response in
let model = self?.updateModel(response)
self?.updateUI(model)
}
Swift Style Guide
Golden Path
When coding with conditionals, the left-hand margin of the code should be the "golden" or "happy" path. That is, don't nest if statements. Multiple return statements are OK. The guard statement is built for this.

Preferred:
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
guard let context = context else {
throw FFTError.noContext
}
guard let inputData = inputData else {
throw FFTError.noInputData
}
// use context and input to compute the frequencies
return frequencies
}
Not Preferred:

func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
if let context = context {
if let inputData = inputData {
// use context and input to compute the frequencies
return frequencies
} else {
throw FFTError.noInputData
}
} else {
throw FFTError.noContext
}
}
When multiple optionals are unwrapped either with guard or if let, minimize nesting by using the compound version when possible. Example:

Preferred:

guard let number1 = number1,
let number2 = number2,
let number3 = number3 else {
fatalError("impossible")
}
// do something with numbers
Not Preferred:

if let number1 = number1 {
if let number2 = number2 {
if let number3 = number3 {
// do something with numbers
} else {
fatalError("impossible")
}
} else {
fatalError("impossible")
}
} else {
fatalError("impossible")
}
Failing Guards
Guard statements are required to exit in some way. Generally, this should be simple one line statement such as return, throw, break, continue, and fatalError(). Large code blocks should be avoided. If cleanup code is required for
multiple exit points, consider using a defer block to avoid cleanup code duplication.
Swift Style Guide
Semicolons
Swift does not require a semicolon after each statement in your code. They are only required if you wish to combine multiple statements
on a single line.

Do not write multiple statements on a single line separated with semicolons.

Preferred:

let swift = "not a scripting language"
Not Preferred:

let swift = "not a scripting language”;
Parentheses
Parentheses around conditionals are not required and should be omitted.

Preferred:

if name == "Hello" {
print("World")
}
Not Preferred:

if (name == "Hello") {
print("World")
}
Swift Style Guide
Organization and Bundle Identifier
Where an Xcode project is involved, the organization should be set to CactusSoft/CactusSoft OOO and the Bundle Identifier set to
com.cactussoft.projectName where projectName is the name of the project.

Never use .dev, .qa, .etc suffixes in Bundle Identifier. Control it in. Build Settings for each configuration.

Swift 4
https://developer.apple.com/library/content/documentation/Swift
Architecture
Never believe “let's do it quickly and then refactor it”
Architecture
MVC
Architecture
MVP
Architecture
MVVM
Architecture
VIPER - it’s simple
Architecture
VIPER + Reactive
Rx
Patterns
xCode Templates
https://github.com/rambler-digital-solutions/Generamba

Generamba is a code generator made for working with Xcode. Primarily it is designed to generate VIPER modules but it is quite easy to
customize it for generation of any other classes (both in Objective-C and Swift).

https://github.com/ochococo/Design-Patterns-In-Swift

Swift 3.0 Design Patterns.
S.O.L.I.D.
Abstractions everywhere!
The Single Responsibility
Principle
class Handler {
 
    func handle() {
        let data = requestDataToAPI()
        let array = parse(data: data)
        saveToDB(array: array)
    }
 
    private func requestDataToAPI() -> Data {
        // send API request and wait the response
    }
 
    private func parse(data: Data) -> [String] {
        // parse the data and create the array
    }
 
    private func saveToDB(array: [String]) {
        // save the array in a database
(CoreData/Realm/...)
    }
}
class Handler {
 
    let apiHandler: APIHandlerProtocol
    let parseHandler: ParseHandlerProtocol
    let dbHandler: DBHandlerProtocol
 
    init(apiHandler: APIHandlerProtocol, parseHandler: ParseHandlerProtocol,
dbHandler: DBHandlerProtocol) {
        self.apiHandler = apiHandler
        self.parseHandler = parseHandler
        self.dbHandler = dbHandler
    }
 
    func handle() {
        let data = apiHandler.requestDataToAPI()
        let array = parseHandler.parse(data: data)
        dbHandler.saveToDB(array: array)
    }
}
 
protocol APIHandlerProtocol {
 
    func requestDataToAPI() -> Data
}
 
protocol ParseHandlerProtocol {
 
    func parse(data: Data) -> [String]
}
 
protocol DBHandlerProtocol {
 
    func saveToDB(array: [String])
}
The Open-Closed Principle
(OCP)
protocol CanShoot {
func shoot() -> String
}
// I'm a laser beam. I can shoot.
final class LaserBeam: CanShoot {
func shoot() -> String {
return "Ziiiiiip!"
}
}
// I have weapons and trust me I can fire them all at once. Boom! Boom! Boom!
final class WeaponsComposite {
let weapons: [CanShoot]
init(weapons: [CanShoot]) {
self.weapons = weapons
}
func shoot() -> [String] {
return weapons.map { $0.shoot() }
}
}
let laser = LaserBeam()
var weapons = WeaponsComposite(weapons: [laser])
weapons.shoot()
final class RocketLauncher: CanShoot {
func shoot() -> String {
return "Whoosh!"
}
}
let rocket = RocketLauncher()
weapons = WeaponsComposite(weapons: [laser, rocket])
weapons.shoot()
The Liskov Substitution
Principle (LSP)
protocol Polygon {
    var area: Float { get }
}
 
class Rectangle: Polygon {
 
    private let width: Float
    private let length: Float
 
    init(width: Float, length: Float) {
        self.width = width
        self.length = length
    }
 
    var area: Float {
        return width * length
    }
}
 
class Square: Polygon {
 
    private let side: Float
 
    init(side: Float) {
        self.side = side
    }
 
    var area: Float {
        return pow(side, 2)
    }
}
 
// Client Method
 
func printArea(of polygon: Polygon) {
    print(polygon.area)
}
 
// Usage
 
let rectangle = Rectangle(width: 2, length: 5)
printArea(of: rectangle) // 10
 
let square = Square(side: 2)
printArea(of: square) // 4
let requestKey: String = "NSURLRequestKey"
// I'm a NSError subclass. I provide additional functionality but don't mess with
original ones.
class RequestError: NSError {
var request: NSURLRequest? {
return self.userInfo[requestKey] as? NSURLRequest
}
}
// I fail to fetch data and will return RequestError.
func fetchData(request: NSURLRequest) -> (data: NSData?, error: RequestError?) {
let userInfo: [String:Any] = [requestKey : request]
return (nil, RequestError(domain:"DOMAIN", code:0, userInfo: userInfo))
}
// I don't know what RequestError is and will fail and return a NSError.
func willReturnObjectOrError() -> (object: AnyObject?, error: NSError?) {
let request = NSURLRequest()
let result = fetchData(request: request)
return (result.data, result.error)
}
let result = willReturnObjectOrError()
// Ok. This is a perfect NSError instance from my perspective.
let error: Int? = result.error?.code
// But hey! What's that? It's also a RequestError! Nice!
if let requestError = result.error as? RequestError {
requestError.request
}
FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT
KNOWING IT.
The Interface Segregation
Principle (ISP)
protocol TapProtocol {
    func didTap()
}
 
protocol DoubleTapProtocol {
    func didDoubleTap()
}
 
protocol LongPressProtocol {
    func didLongPress()
}
 
class SuperButton: TapProtocol, DoubleTapProtocol, LongPressProtocol {
    func didTap() {
        // send tap action
    }
 
    func didDoubleTap() {
        // send double tap action
    }
 
    func didLongPress() {
        // send long press action
    }
}
 
class PoorButton: TapProtocol {
    func didTap() {
        // send tap action
    }
}
CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE.
The Dependency Inversion
Principle (DIP)
class Handler {
 
    let storage: Storage
 
    init(storage: Storage) {
        self.storage = storage
    }
 
    func handle(string: String) {
        storage.save(string: string)
    }
}
 
protocol Storage {
 
   func save(string: String)
}
 
class FilesystemManager: Storage {
 
    func save(string: String) {
        // Open a file in read-mode
        // Save the string in this file
        // Close the file
    }
}
 
class DatabaseManager: Storage {
 
    func save(string: String) {
        // Connect to the database
        // Execute the query to save the string in a table
        // Close the connection
    }
}
A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.
B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.
Project Setup
Make your development more comfortable
Project Setup
Project Structure
To keep all those hundreds of source files from ending up in the same directory, it's a good idea to set up some folder structure depending
on your architecture. For instance, you can use the following:

├─ Models
├─ Views
├─ Controllers (or ViewModels, if your architecture is MVVM)
├─ Stores
├─ Extensions
├─ Utils
├─ Helpers
├─ etc…
Localization
Keep all user strings in localization files right from the beginning. This is good not only for translations, but also for finding user-facing text
quickly. You can add a launch argument to your build scheme to launch the app in a certain language, e.g.

-AppleLanguages (Finnish)
For more complex translations such as plural forms that depending on a number of items (e.g. "1 person" vs. "3 people"), you should use
the .stringsdict format instead of a regular localizable.strings file.

Constants
Keep your constants' scope as small as possible. For instance, when you only need it inside a class, it should live in that class. Those
constants that need to be truly app-wide should be kept in one place. In Swift, you can use structs defined in a Constants.swift file to
group, store and access your app-wide constants in a clean way:

struct Config {
static let baseURL = NSURL(string: "http://www.example.org/")!
static let splineReticulatorName = "foobar"
}
struct Color {
static let primaryColor = UIColor(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0)
static let secondaryColor = UIColor.lightGrayColor()
}
Project Setup
Project Structure
To keep all those hundreds of source files from ending up in the same directory, it's a good idea to set up some folder structure depending
on your architecture. For instance, you can use the following:

├─ Models
├─ Views
├─ Controllers (or ViewModels, if your architecture is MVVM)
├─ Stores
├─ Extensions
├─ Utils
├─ Helpers
├─ etc…
Localization
Keep all user strings in localization files right from the beginning. This is good not only for translations, but also for finding user-facing text
quickly. You can add a launch argument to your build scheme to launch the app in a certain language, e.g.

-AppleLanguages (Finnish)
For more complex translations such as plural forms that depending on a number of items (e.g. "1 person" vs. "3 people"), you should use
the .stringsdict format instead of a regular localizable.strings file.

Constants
Keep your constants' scope as small as possible. For instance, when you only need it inside a class, it should live in that class. Those
constants that need to be truly app-wide should be kept in one place. In Swift, you can use structs defined in a Constants.swift file to
group, store and access your app-wide constants in a clean way:

struct Config {
static let baseURL = NSURL(string: "http://www.example.org/")!
static let splineReticulatorName = "foobar"
}
struct Color {
static let primaryColor = UIColor(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0)
static let secondaryColor = UIColor.lightGrayColor()
}
Project Setup
Minimum iOS Version Requirement
It’s useful to make an early decision on the minimum iOS version you want to support in your project: knowing which OS versions you need to develop
and test against, and which system APIs you can rely on, helps you estimate your workload, and enables you to determine what’s possible and what’s
not.

Use these resources to gather the data necessary for making this choice:

	 •	 Official “first-party” resources:

	 ◦	 Apple’s world-wide iOS version penetration statistics: The primary public source for version penetration stats. Prefer more localized and
domain-specific statistics, if available.

Common Libraries
Generally speaking, make it a conscious decision to add an external dependency to your project. Sure, this one neat library solves your problem now, but
maybe later gets stuck in maintenance limbo, with the next OS version that breaks everything being just around the corner. Another scenario is that a
feature only achievable with external libraries suddenly becomes part of the official APIs. In a well-designed codebase, switching out the implementation
is a small effort that pays off quickly. Always consider solving the problem using Apple's extensive (and mostly excellent) frameworks first!

# UI Components
pod ‘JTCalendar’
pod 'DZNEmptyDataSet'
pod 'ActionSheetPicker-3.0'
pod 'MBProgressHUD'
pod 'PasswordTextField'
pod 'MaterialControls'
pod 'MGSwipeTableCell'
pod 'Floaty'
pod 'JDStatusBarNotification'
pod 'Magnetic'
Common Libraries
# UI Customization
pod 'PureLayout'
pod 'SnapKit'
pod ‘UIColor_Hex_Swift'
pod ‘SwiftHEXColors’
# Rate App
pod 'Armchair'
pod ‘iRate'
# Camera / Photo
pod 'MHVideoPhotoGallery'
pod 'LLSimpleCamera'
# Bug Tracking
pod 'Fabric'
pod 'Crashlytics'
# Analytics
pod 'GoogleAnalytics'
pod 'GoogleSignIn'
pod 'Appsee'
pod 'Taplytics', '2.17.6'
pod 'FBSDKCoreKit'
pod 'Localytics'
pod 'NewRelicAgent'
pod 'KochavaTrackeriOS'
pod 'Mixpanel-swift'
pod 'Branch'
# Reactive
pod 'RxSwift'
pod 'RxCocoa'
# Charts
pod 'Charts'
pod 'ChartsRealm'
Common Libraries
# Network
pod 'Moya'
pod 'Alamofire'
pod 'SwiftyJSON'
pod ‘SDWebImage'
pod ‘KFSwiftImageLoader’
# Cloud
pod 'Dropbox-iOS-Dropins-SDK'
pod 'box-ios-browse-sdk'
pod 'GoogleAPIClientForREST/Drive'
pod 'GTMOAuth2'
# Address Book Data
pod 'APAddressBook'
pod 'libPhoneNumber-iOS'
# Communication With Customers
pod 'Intercom'
# AB Testing
pod 'Firebase/Core'
pod 'Firebase/DynamicLinks'
pod 'Firebase/Performance'
pod 'GoogleTagManager'
# Debug
pod 'Dotzu'
# Data Storage
pod ‘RealmSwift'
pod ‘KeychainAccess'
# Common
pod ‘Localize-Swift’
pod ‘DateTools’
# Billing
pod ‘SwiftyStoreKit'
Continuous Integration and Delivery
Process
Optimize you time
CI and CD
Setting up a continuous integration and delivery process has become critical nowadays as it helps you to
squash out bugs early in the development cycle and saves a lot of developer time.
Continuous Integration (CI) is a development practice that requires developers to integrate code into a
shared repository several times a day. Each check-in is then verified by an automated build, allowing
teams to detect problems early.
There are a lot of tools available that can help you with continuous integration of iOS apps like Xcode
Server, Jenkins and Travis CI.
Continuous Delivery (CD) is a software engineering approach in which teams produce software in short
cycles, ensuring that the software can be reliably released at any time. It aims at building, testing, and
releasing software faster and more frequently.
Why use Continuous Delivery?
1.Save days of preparing app submission, uploading screenshots and releasing the app
2.Colleague on vacation and a critical bugfix needs to be released? Don’t rely on one person releasing
updates
3. Increase software quality and reaction time with more frequent and smaller releases
iOS best practices

More Related Content

What's hot

Javascript best practices
Javascript best practicesJavascript best practices
Javascript best practicesManav Gupta
 
Asp 4-razor-introduction of view engine
Asp 4-razor-introduction of view engineAsp 4-razor-introduction of view engine
Asp 4-razor-introduction of view engineFajar Baskoro
 
Javascript part1
Javascript part1Javascript part1
Javascript part1Raghu nath
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to JavascriptAmit Tyagi
 
Flex Maniacs 2007
Flex Maniacs 2007Flex Maniacs 2007
Flex Maniacs 2007rtretola
 
Introduction to Design Patterns in Javascript
Introduction to Design Patterns in JavascriptIntroduction to Design Patterns in Javascript
Introduction to Design Patterns in JavascriptSanthosh Kumar Srinivasan
 
Asp.net MVC - Course 2
Asp.net MVC - Course 2Asp.net MVC - Course 2
Asp.net MVC - Course 2erdemergin
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Librariesjeresig
 
Building maintainable javascript applications
Building maintainable javascript applicationsBuilding maintainable javascript applications
Building maintainable javascript applicationsequisodie
 
MVC Design Pattern in JavaScript by ADMEC Multimedia Institute
MVC Design Pattern in JavaScript by ADMEC Multimedia InstituteMVC Design Pattern in JavaScript by ADMEC Multimedia Institute
MVC Design Pattern in JavaScript by ADMEC Multimedia InstituteRavi Bhadauria
 
STC 2016 Programming Language Storytime
STC 2016 Programming Language StorytimeSTC 2016 Programming Language Storytime
STC 2016 Programming Language StorytimeSarah Kiniry
 
Patterns for JVM languages - Geecon 2014
Patterns for JVM languages - Geecon 2014Patterns for JVM languages - Geecon 2014
Patterns for JVM languages - Geecon 2014Jaroslaw Palka
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript ProgrammingSehwan Noh
 

What's hot (20)

Javascript best practices
Javascript best practicesJavascript best practices
Javascript best practices
 
Javascript
JavascriptJavascript
Javascript
 
Asp 4-razor-introduction of view engine
Asp 4-razor-introduction of view engineAsp 4-razor-introduction of view engine
Asp 4-razor-introduction of view engine
 
Books
BooksBooks
Books
 
Javascript part1
Javascript part1Javascript part1
Javascript part1
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to Javascript
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
Flex Maniacs 2007
Flex Maniacs 2007Flex Maniacs 2007
Flex Maniacs 2007
 
Introduction to Design Patterns in Javascript
Introduction to Design Patterns in JavascriptIntroduction to Design Patterns in Javascript
Introduction to Design Patterns in Javascript
 
Java script
Java scriptJava script
Java script
 
Asp.net MVC - Course 2
Asp.net MVC - Course 2Asp.net MVC - Course 2
Asp.net MVC - Course 2
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
 
Building maintainable javascript applications
Building maintainable javascript applicationsBuilding maintainable javascript applications
Building maintainable javascript applications
 
MVC Design Pattern in JavaScript by ADMEC Multimedia Institute
MVC Design Pattern in JavaScript by ADMEC Multimedia InstituteMVC Design Pattern in JavaScript by ADMEC Multimedia Institute
MVC Design Pattern in JavaScript by ADMEC Multimedia Institute
 
STC 2016 Programming Language Storytime
STC 2016 Programming Language StorytimeSTC 2016 Programming Language Storytime
STC 2016 Programming Language Storytime
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Patterns for JVM languages - Geecon 2014
Patterns for JVM languages - Geecon 2014Patterns for JVM languages - Geecon 2014
Patterns for JVM languages - Geecon 2014
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript Programming
 
Java script basic
Java script basicJava script basic
Java script basic
 
Java script
Java scriptJava script
Java script
 

Similar to iOS best practices

Intro to iOS Development • Made by Many
Intro to iOS Development • Made by ManyIntro to iOS Development • Made by Many
Intro to iOS Development • Made by Manykenatmxm
 
Angular JS2 Training Session #1
Angular JS2 Training Session #1Angular JS2 Training Session #1
Angular JS2 Training Session #1Paras Mendiratta
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)David McCarter
 
Cocoa for Web Developers
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developersgeorgebrock
 
My 70-480 HTML5 certification learning
My 70-480 HTML5 certification learningMy 70-480 HTML5 certification learning
My 70-480 HTML5 certification learningSyed Irtaza Ali
 
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra  SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra Sencha
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6Nitay Neeman
 
Back-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldBack-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldDavid McCarter
 
Back-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldBack-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldDavid McCarter
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLsintelliyole
 
Styled components presentation
Styled components presentationStyled components presentation
Styled components presentationMaciej Matuszewski
 
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxUnit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxMalla Reddy University
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsMaciej Burda
 
Effecient javascript
Effecient javascriptEffecient javascript
Effecient javascriptmpnkhan
 

Similar to iOS best practices (20)

Intro to iOS Development • Made by Many
Intro to iOS Development • Made by ManyIntro to iOS Development • Made by Many
Intro to iOS Development • Made by Many
 
Angular JS2 Training Session #1
Angular JS2 Training Session #1Angular JS2 Training Session #1
Angular JS2 Training Session #1
 
Swift, swiftly
Swift, swiftlySwift, swiftly
Swift, swiftly
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)
 
Objective c slide I
Objective c slide IObjective c slide I
Objective c slide I
 
Cocoa for Web Developers
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developers
 
My 70-480 HTML5 certification learning
My 70-480 HTML5 certification learningMy 70-480 HTML5 certification learning
My 70-480 HTML5 certification learning
 
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra  SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
 
Scala idioms
Scala idiomsScala idioms
Scala idioms
 
iOS Application Development
iOS Application DevelopmentiOS Application Development
iOS Application Development
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6
 
Back-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldBack-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real World
 
Back-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real WorldBack-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real World
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
 
Styled components presentation
Styled components presentationStyled components presentation
Styled components presentation
 
Robots in Swift
Robots in SwiftRobots in Swift
Robots in Swift
 
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxUnit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design Patterns
 
Effecient javascript
Effecient javascriptEffecient javascript
Effecient javascript
 

Recently uploaded

Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsMehedi Hasan Shohan
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 

Recently uploaded (20)

Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software Solutions
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 

iOS best practices

  • 1. iOS bad Best Practices Do not scold the code - make it better
  • 2. Setup the coding style Oops… I missed something again
  • 3. Objective-C Style Guide Dot Notation Syntax Dot notation is RECOMMENDED over bracket notation for getting and setting properties. For example: view.backgroundColor = [UIColor orangeColor]; [UIApplication sharedApplication].delegate; Not: [view setBackgroundColor:[UIColor orangeColor]]; UIApplication.sharedApplication.delegate; Spacing Method braces and other braces (if/else/switch/while etc.) MUST open on the same line as the statement. Braces MUST close on a new line. For example: if (user.isHappy) { // Do something } else { // Do something else } Not: if (user.isHappy) { // Do something } else { // Do something else } Conditionals For example: if (!error) { return success; } Not: if (!error) return success; or if (!error) return success;
  • 4. Objective-C Style Guide Ternary Operator The intent of the ternary operator, ? , is to increase clarity or code neatness. The ternary SHOULD only evaluate a single condition per expression. Evaluating multiple conditions is usually more understandable as an if statement or refactored into named variables. For example: result = a > b ? x : y; Not: result = a > b ? x = c > d ? c : d : y; Methods In method signatures, there SHOULD be a space after the scope (- or + symbol). There SHOULD be a space between the method segments. For example: - (void)setExampleText:(NSString *)text image:(UIImage *)image; Not: +(void)openSignInVC; Variables Variables SHOULD be named descriptively, with the variable’s name clearly communicating what the variable is and pertinent information a programmer needs to use that value properly. For example: • NSString *title: It is reasonable to assume a “title” is a string. • NSString *titleHTML: This indicates a title that may contain HTML which needs parsing for display. “HTML” is needed for a programmer to use this variable effectively. Asterisks indicating a type is a pointer MUST be “attached to” the variable name. For example, NSString *text not NSString* text or NSString * text, except in the case of constants (NSString * const NYTConstantString). Variable Qualifiers When it comes to the variable qualifiers introduced with ARC, the qualifier (__strong, __weak, __unsafe_unretained, __autoreleasing) SHOULD be placed between the asterisks and the variable name, e.g., NSString * __weak text.
  • 5. Objective-C Style Guide Naming Apple naming conventions SHOULD be adhered to wherever possible, especially those related to memory management rules (NARC). Long, descriptive method and variable names are good. For example: UIButton *settingsButton; Not UIButton *setBut; For example: static const NSTimeInterval NYTArticleViewControllerNavigationFadeAnimationDuration = 0.3; Not: static const NSTimeInterval fadetime = 1.7; Categories Categories are RECOMMENDED to concisely segment functionality and should be named to describe that functionality. For example: @interface UIViewController (NYTMediaPlaying) @interface NSString (NSStringEncodingDetection) Not: @interface NYTAdvertisement (private) @interface NSString (NYTAdditions) Methods and properties added in categories MUST be named with an app- or organization-specific prefix. This avoids unintentionally overriding an existing method, and it reduces the chance of two categories from different libraries adding a method of the same name. (The Objective-C runtime doesn’t specify which method will be called in the latter case, which can lead to unintended effects.) For example: @interface NSArray (NYTAccessors) - (id)nyt_objectOrNilAtIndex:(NSUInteger)index; @end Not: @interface NSArray (NYTAccessors) - (id)objectOrNilAtIndex:(NSUInteger)index; @end
  • 6. Objective-C Style Guide Comments When they are needed, comments SHOULD be used to explain why a particular piece of code does something. Any comments that are used MUST be kept up-to-date or deleted. No comment Not: // Start monitoring network connection [Reachability defaultReachability]; Literals NSString, NSDictionary, NSArray, and NSNumber literals SHOULD be used whenever creating immutable instances of those objects. Pay special care that nil values not be passed into NSArray and NSDictionary literals, as this will cause a crash. For example: NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"]; NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"}; NSNumber *shouldUseLiterals = @YES; NSNumber *buildingZIPCode = @10018; Not: NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil]; NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil]; NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES]; NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018]; Constants Constants are RECOMMENDED over in-line string literals or numbers, as they allow for easy reproduction of commonly used variables and can be quickly changed without the need for find and replace. Constants MUST be declared as static constants. Constants MAY be declared as #define when explicitly being used as a macro. For example: static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company"; static const CGFloat NYTImageThumbnailHeight = 50.0; Not: #define CompanyName @"The New York Times Company" #define thumbnailHeight 2 fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling
  • 7. Objective-C Style Guide Booleans Values MUST NOT be compared directly to YES, because YES is defined as 1, and a BOOL in Objective-C is a CHAR type that is 8 bits long (so a value of 11111110 will return NO if compared to YES). For a BOOL value: if (isAwesome) if (!someNumber.boolValue) if (someNumber.boolValue == NO) Not: if (isAwesome == YES) // Never do this. Imports If there is more than one import statement, statements MUST be grouped together. Groups MAY be commented. // Frameworks @import QuartzCore; // Models #import "NYTUser.h" // Views #import "NYTButton.h" #import “NYTUserView.h" https://github.com/NYTimes/objective-c-style-guide
  • 8. Setup the coding style How it appears in Swift
  • 9. Swift Style Guide Spacing Preferred: if user.isHappy { // Do something } else { // Do something else } Not Preferred: if user.isHappy { // Do something } else { // Do something else } • There should be exactly one blank line between methods to aid in visual clarity and organization. Whitespace within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods. override func viewDidLoad() { super.viewDidLoad() setup() validate() } • Colons always have no space on the left and one space on the right. Exceptions are the ternary operator ? :, empty dictionary [:] and #selector syntax for unnamed parameters (_:). Preferred: class TestDatabase: Database { var data: [String: CGFloat] = ["A": 1.2, "B": 3.2] } Not Preferred: class TestDatabase : Database { var data :[String:CGFloat] = ["A" : 1.2, "B":3.2] }
  • 10. Swift Style Guide Comments When they are needed, use comments to explain why a particular piece of code does something. Comments must be kept up-to-date or deleted. Avoid block comments inline with code, as the code should be as self-documenting as possible. Exception: This does not apply to those comments used to generate documentation. Delegates When creating custom delegate methods, an unnamed first parameter should be the delegate source. (UIKit contains numerous examples of this.) Preferred: func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String) func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool Not Preferred: func didSelectName(namePicker: NamePickerViewController, name: String) func namePickerShouldReload() -> Bool Use Type Inferred Context Use compiler inferred context to write shorter, clear code. (Also see Type Inference.) Preferred: let selector = #selector(viewDidLoad) view.backgroundColor = .red let toView = context.view(forKey: .to) let view = UIView(frame: .zero) Not Preferred: let selector = #selector(ViewController.viewDidLoad) view.backgroundColor = UIColor.red let toView = context.view(forKey: UITransitionContextViewKey.to) let view = UIView(frame: CGRect.zero)
  • 11. Swift Style Guide Code Organization Use extensions to organize your code into logical blocks of functionality. Each extension should be set off with a // MARK: - comment to keep things well-organized. Protocol Conformance In particular, when adding protocol conformance to a model, prefer adding a separate extension for the protocol methods. This keeps the related methods grouped together with the protocol and can simplify instructions to add a protocol to a class with its associated methods. Preferred: class MyViewController: UIViewController { // class stuff here } // MARK: - UITableViewDataSource extension MyViewController: UITableViewDataSource { // table view data source methods } // MARK: - UIScrollViewDelegate extension MyViewController: UIScrollViewDelegate { // scroll view delegate methods } Not Preferred: class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate { // all methods }
  • 12. Swift Style Guide Unused Code Unused (dead) code, including Xcode template code and placeholder comments should be removed. An exception is when your tutorial or book instructs the user to use the commented code. Aspirational methods not directly associated with the tutorial whose implementation simply calls the superclass should also be removed. This includes any empty/unused UIApplicationDelegate methods. Preferred: override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return Database.contacts.count } Not Preferred: override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } override func numberOfSections(in tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return Database.contacts.count } Minimal Imports Keep imports minimal. For example, don't import UIKit when importing Foundation will suffice.
  • 13. Swift Style Guide Classes and Structures Remember, structs have value semantics. Classes have reference semantics. NOTE Structures are always copied when they are passed around in your code, and do not use reference counting. NOTE However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. Use of Self For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods. Use self only when required by the compiler (in @escaping closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without self then omit it. Computed Properties For conciseness, if a computed property is read-only, omit the get clause. The get clause is required only when a set clause is provided. Preferred: var diameter: Double { return radius * 2 } Not Preferred: var diameter: Double { get { return radius * 2 } }
  • 14. Swift Style Guide Final Marking classes or members as final in tutorials can distract from the main topic and is not required. Nevertheless, use of final can sometimes clarify your intent and is worth the cost. In the below example, Box has a particular purpose and customization in a derived class is not intended. Marking it final makes that clear. // Turn any generic type into a reference type using this Box class. final class Box<T> { let value: T init(_ value: T) { self.value = value } } Function Declarations Keep short function declarations on one line including the opening brace: func reticulateSplines(spline: [Double]) -> Bool { // reticulate code goes here } For functions with long signatures, add line breaks at appropriate points and add an extra indent on subsequent lines: func reticulateSplines(spline: [Double], adjustmentFactor: Double, translateConstant: Int, comment: String) -> Bool { // reticulate code goes here } Closure Expressions Use trailing closure syntax only if there's a single closure expression parameter at the end of the argument list. Give the closure parameters descriptive names. Preferred: UIView.animate(withDuration: 1.0) { self.myView.alpha = 0 } UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0 }, completion: { finished in self.myView.removeFromSuperview() }) Not Preferred: UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0 }) UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0 }) { f in self.myView.removeFromSuperview() }
  • 15. Swift Style Guide Constants Type properties declared in this way are generally preferred over global constants because they are easier to distinguish from instance properties. Example: Preferred: enum Math { static let e = 2.718281828459045235360287 static let root2 = 1.41421356237309504880168872 } let hypotenuse = side * Math.root2 Optionals Preferred: var subview: UIView? var volume: Double? // later on... if let subview = subview, let volume = volume { // do something with unwrapped subview and volume } Not Preferred: var optionalSubview: UIView? var volume: Double? if let unwrappedSubview = optionalSubview { if let realVolume = volume { // do something with unwrappedSubview and realVolume } }
  • 16. Swift Style Guide Lazy Initialization Consider using lazy initialization for finer grain control over object lifetime. This is especially true for UIViewController that loads views lazily. You can either use a closure that is immediately called { }() or call a private factory method. Example: lazy var locationManager: CLLocationManager = self.makeLocationManager() private func makeLocationManager() -> CLLocationManager { let manager = CLLocationManager() manager.desiredAccuracy = kCLLocationAccuracyBest manager.delegate = self manager.requestAlwaysAuthorization() return manager } Type Inference Prefer compact code and let the compiler infer the type for constants or variables of single instances. Type inference is also appropriate for small (non-empty) arrays and dictionaries. When required, specify the specific type such as CGFloat or Int16. Preferred: let message = "Click the button" let currentBounds = computeViewBounds() var names = ["Mic", "Sam", "Christine"] let maximumWidth: CGFloat = 106.5 Not Preferred: let message: String = "Click the button" let currentBounds: CGRect = computeViewBounds() let names = [String]() Syntactic Sugar Prefer the shortcut versions of type declarations over the full generics syntax. Preferred: var deviceModels: [String] var employees: [Int: String] var faxNumber: Int? Not Preferred: var deviceModels: Array<String> var employees: Dictionary<Int, String> var faxNumber: Optional<Int>
  • 17. Swift Style Guide Memory Management Code (even non-production, tutorial demo code) should not create reference cycles. Analyze your object graph and prevent strong cycles with weak and unowned references. Alternatively, use value types (struct, enum) to prevent cycles altogether. Extending object lifetime Extend object lifetime using the [weak self] and guard let strongSelf = self else { return } idiom. [weak self] is preferred to [unowned self] where it is not immediately obvious that self outlives the closure. Explicitly extending lifetime is preferred to optional unwrapping. Preferred resource.request().onComplete { [weak self] response in guard let strongSelf = self else { return } let model = strongSelf.updateModel(response) strongSelf.updateUI(model) } Not Preferred // might crash if self is released before response returns resource.request().onComplete { [unowned self] response in let model = self.updateModel(response) self.updateUI(model) } Not Preferred // deallocate could happen between updating the model and updating UI resource.request().onComplete { [weak self] response in let model = self?.updateModel(response) self?.updateUI(model) }
  • 18. Swift Style Guide Golden Path When coding with conditionals, the left-hand margin of the code should be the "golden" or "happy" path. That is, don't nest if statements. Multiple return statements are OK. The guard statement is built for this. Preferred: func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies { guard let context = context else { throw FFTError.noContext } guard let inputData = inputData else { throw FFTError.noInputData } // use context and input to compute the frequencies return frequencies } Not Preferred: func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies { if let context = context { if let inputData = inputData { // use context and input to compute the frequencies return frequencies } else { throw FFTError.noInputData } } else { throw FFTError.noContext } } When multiple optionals are unwrapped either with guard or if let, minimize nesting by using the compound version when possible. Example: Preferred: guard let number1 = number1, let number2 = number2, let number3 = number3 else { fatalError("impossible") } // do something with numbers Not Preferred: if let number1 = number1 { if let number2 = number2 { if let number3 = number3 { // do something with numbers } else { fatalError("impossible") } } else { fatalError("impossible") } } else { fatalError("impossible") } Failing Guards Guard statements are required to exit in some way. Generally, this should be simple one line statement such as return, throw, break, continue, and fatalError(). Large code blocks should be avoided. If cleanup code is required for multiple exit points, consider using a defer block to avoid cleanup code duplication.
  • 19. Swift Style Guide Semicolons Swift does not require a semicolon after each statement in your code. They are only required if you wish to combine multiple statements on a single line. Do not write multiple statements on a single line separated with semicolons. Preferred: let swift = "not a scripting language" Not Preferred: let swift = "not a scripting language”; Parentheses Parentheses around conditionals are not required and should be omitted. Preferred: if name == "Hello" { print("World") } Not Preferred: if (name == "Hello") { print("World") }
  • 20. Swift Style Guide Organization and Bundle Identifier Where an Xcode project is involved, the organization should be set to CactusSoft/CactusSoft OOO and the Bundle Identifier set to com.cactussoft.projectName where projectName is the name of the project. Never use .dev, .qa, .etc suffixes in Bundle Identifier. Control it in. Build Settings for each configuration. Swift 4 https://developer.apple.com/library/content/documentation/Swift
  • 21. Architecture Never believe “let's do it quickly and then refactor it”
  • 27. Patterns xCode Templates https://github.com/rambler-digital-solutions/Generamba Generamba is a code generator made for working with Xcode. Primarily it is designed to generate VIPER modules but it is quite easy to customize it for generation of any other classes (both in Objective-C and Swift). https://github.com/ochococo/Design-Patterns-In-Swift Swift 3.0 Design Patterns.
  • 29. The Single Responsibility Principle class Handler {       func handle() {         let data = requestDataToAPI()         let array = parse(data: data)         saveToDB(array: array)     }       private func requestDataToAPI() -> Data {         // send API request and wait the response     }       private func parse(data: Data) -> [String] {         // parse the data and create the array     }       private func saveToDB(array: [String]) {         // save the array in a database (CoreData/Realm/...)     } } class Handler {       let apiHandler: APIHandlerProtocol     let parseHandler: ParseHandlerProtocol     let dbHandler: DBHandlerProtocol       init(apiHandler: APIHandlerProtocol, parseHandler: ParseHandlerProtocol, dbHandler: DBHandlerProtocol) {         self.apiHandler = apiHandler         self.parseHandler = parseHandler         self.dbHandler = dbHandler     }       func handle() {         let data = apiHandler.requestDataToAPI()         let array = parseHandler.parse(data: data)         dbHandler.saveToDB(array: array)     } }   protocol APIHandlerProtocol {       func requestDataToAPI() -> Data }   protocol ParseHandlerProtocol {       func parse(data: Data) -> [String] }   protocol DBHandlerProtocol {       func saveToDB(array: [String]) }
  • 30. The Open-Closed Principle (OCP) protocol CanShoot { func shoot() -> String } // I'm a laser beam. I can shoot. final class LaserBeam: CanShoot { func shoot() -> String { return "Ziiiiiip!" } } // I have weapons and trust me I can fire them all at once. Boom! Boom! Boom! final class WeaponsComposite { let weapons: [CanShoot] init(weapons: [CanShoot]) { self.weapons = weapons } func shoot() -> [String] { return weapons.map { $0.shoot() } } } let laser = LaserBeam() var weapons = WeaponsComposite(weapons: [laser]) weapons.shoot() final class RocketLauncher: CanShoot { func shoot() -> String { return "Whoosh!" } } let rocket = RocketLauncher() weapons = WeaponsComposite(weapons: [laser, rocket]) weapons.shoot()
  • 31. The Liskov Substitution Principle (LSP) protocol Polygon {     var area: Float { get } }   class Rectangle: Polygon {       private let width: Float     private let length: Float       init(width: Float, length: Float) {         self.width = width         self.length = length     }       var area: Float {         return width * length     } }   class Square: Polygon {       private let side: Float       init(side: Float) {         self.side = side     }       var area: Float {         return pow(side, 2)     } }   // Client Method   func printArea(of polygon: Polygon) {     print(polygon.area) }   // Usage   let rectangle = Rectangle(width: 2, length: 5) printArea(of: rectangle) // 10   let square = Square(side: 2) printArea(of: square) // 4 let requestKey: String = "NSURLRequestKey" // I'm a NSError subclass. I provide additional functionality but don't mess with original ones. class RequestError: NSError { var request: NSURLRequest? { return self.userInfo[requestKey] as? NSURLRequest } } // I fail to fetch data and will return RequestError. func fetchData(request: NSURLRequest) -> (data: NSData?, error: RequestError?) { let userInfo: [String:Any] = [requestKey : request] return (nil, RequestError(domain:"DOMAIN", code:0, userInfo: userInfo)) } // I don't know what RequestError is and will fail and return a NSError. func willReturnObjectOrError() -> (object: AnyObject?, error: NSError?) { let request = NSURLRequest() let result = fetchData(request: request) return (result.data, result.error) } let result = willReturnObjectOrError() // Ok. This is a perfect NSError instance from my perspective. let error: Int? = result.error?.code // But hey! What's that? It's also a RequestError! Nice! if let requestError = result.error as? RequestError { requestError.request } FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.
  • 32. The Interface Segregation Principle (ISP) protocol TapProtocol {     func didTap() }   protocol DoubleTapProtocol {     func didDoubleTap() }   protocol LongPressProtocol {     func didLongPress() }   class SuperButton: TapProtocol, DoubleTapProtocol, LongPressProtocol {     func didTap() {         // send tap action     }       func didDoubleTap() {         // send double tap action     }       func didLongPress() {         // send long press action     } }   class PoorButton: TapProtocol {     func didTap() {         // send tap action     } } CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE.
  • 33. The Dependency Inversion Principle (DIP) class Handler {       let storage: Storage       init(storage: Storage) {         self.storage = storage     }       func handle(string: String) {         storage.save(string: string)     } }   protocol Storage {      func save(string: String) }   class FilesystemManager: Storage {       func save(string: String) {         // Open a file in read-mode         // Save the string in this file         // Close the file     } }   class DatabaseManager: Storage {       func save(string: String) {         // Connect to the database         // Execute the query to save the string in a table         // Close the connection     } } A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS. B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.
  • 34. Project Setup Make your development more comfortable
  • 35. Project Setup Project Structure To keep all those hundreds of source files from ending up in the same directory, it's a good idea to set up some folder structure depending on your architecture. For instance, you can use the following: ├─ Models ├─ Views ├─ Controllers (or ViewModels, if your architecture is MVVM) ├─ Stores ├─ Extensions ├─ Utils ├─ Helpers ├─ etc… Localization Keep all user strings in localization files right from the beginning. This is good not only for translations, but also for finding user-facing text quickly. You can add a launch argument to your build scheme to launch the app in a certain language, e.g. -AppleLanguages (Finnish) For more complex translations such as plural forms that depending on a number of items (e.g. "1 person" vs. "3 people"), you should use the .stringsdict format instead of a regular localizable.strings file. Constants Keep your constants' scope as small as possible. For instance, when you only need it inside a class, it should live in that class. Those constants that need to be truly app-wide should be kept in one place. In Swift, you can use structs defined in a Constants.swift file to group, store and access your app-wide constants in a clean way: struct Config { static let baseURL = NSURL(string: "http://www.example.org/")! static let splineReticulatorName = "foobar" } struct Color { static let primaryColor = UIColor(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0) static let secondaryColor = UIColor.lightGrayColor() }
  • 36. Project Setup Project Structure To keep all those hundreds of source files from ending up in the same directory, it's a good idea to set up some folder structure depending on your architecture. For instance, you can use the following: ├─ Models ├─ Views ├─ Controllers (or ViewModels, if your architecture is MVVM) ├─ Stores ├─ Extensions ├─ Utils ├─ Helpers ├─ etc… Localization Keep all user strings in localization files right from the beginning. This is good not only for translations, but also for finding user-facing text quickly. You can add a launch argument to your build scheme to launch the app in a certain language, e.g. -AppleLanguages (Finnish) For more complex translations such as plural forms that depending on a number of items (e.g. "1 person" vs. "3 people"), you should use the .stringsdict format instead of a regular localizable.strings file. Constants Keep your constants' scope as small as possible. For instance, when you only need it inside a class, it should live in that class. Those constants that need to be truly app-wide should be kept in one place. In Swift, you can use structs defined in a Constants.swift file to group, store and access your app-wide constants in a clean way: struct Config { static let baseURL = NSURL(string: "http://www.example.org/")! static let splineReticulatorName = "foobar" } struct Color { static let primaryColor = UIColor(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0) static let secondaryColor = UIColor.lightGrayColor() }
  • 37. Project Setup Minimum iOS Version Requirement It’s useful to make an early decision on the minimum iOS version you want to support in your project: knowing which OS versions you need to develop and test against, and which system APIs you can rely on, helps you estimate your workload, and enables you to determine what’s possible and what’s not. Use these resources to gather the data necessary for making this choice: • Official “first-party” resources: ◦ Apple’s world-wide iOS version penetration statistics: The primary public source for version penetration stats. Prefer more localized and domain-specific statistics, if available. Common Libraries Generally speaking, make it a conscious decision to add an external dependency to your project. Sure, this one neat library solves your problem now, but maybe later gets stuck in maintenance limbo, with the next OS version that breaks everything being just around the corner. Another scenario is that a feature only achievable with external libraries suddenly becomes part of the official APIs. In a well-designed codebase, switching out the implementation is a small effort that pays off quickly. Always consider solving the problem using Apple's extensive (and mostly excellent) frameworks first! # UI Components pod ‘JTCalendar’ pod 'DZNEmptyDataSet' pod 'ActionSheetPicker-3.0' pod 'MBProgressHUD' pod 'PasswordTextField' pod 'MaterialControls' pod 'MGSwipeTableCell' pod 'Floaty' pod 'JDStatusBarNotification' pod 'Magnetic'
  • 38. Common Libraries # UI Customization pod 'PureLayout' pod 'SnapKit' pod ‘UIColor_Hex_Swift' pod ‘SwiftHEXColors’ # Rate App pod 'Armchair' pod ‘iRate' # Camera / Photo pod 'MHVideoPhotoGallery' pod 'LLSimpleCamera' # Bug Tracking pod 'Fabric' pod 'Crashlytics' # Analytics pod 'GoogleAnalytics' pod 'GoogleSignIn' pod 'Appsee' pod 'Taplytics', '2.17.6' pod 'FBSDKCoreKit' pod 'Localytics' pod 'NewRelicAgent' pod 'KochavaTrackeriOS' pod 'Mixpanel-swift' pod 'Branch' # Reactive pod 'RxSwift' pod 'RxCocoa' # Charts pod 'Charts' pod 'ChartsRealm'
  • 39. Common Libraries # Network pod 'Moya' pod 'Alamofire' pod 'SwiftyJSON' pod ‘SDWebImage' pod ‘KFSwiftImageLoader’ # Cloud pod 'Dropbox-iOS-Dropins-SDK' pod 'box-ios-browse-sdk' pod 'GoogleAPIClientForREST/Drive' pod 'GTMOAuth2' # Address Book Data pod 'APAddressBook' pod 'libPhoneNumber-iOS' # Communication With Customers pod 'Intercom' # AB Testing pod 'Firebase/Core' pod 'Firebase/DynamicLinks' pod 'Firebase/Performance' pod 'GoogleTagManager' # Debug pod 'Dotzu' # Data Storage pod ‘RealmSwift' pod ‘KeychainAccess' # Common pod ‘Localize-Swift’ pod ‘DateTools’ # Billing pod ‘SwiftyStoreKit'
  • 40. Continuous Integration and Delivery Process Optimize you time
  • 41. CI and CD Setting up a continuous integration and delivery process has become critical nowadays as it helps you to squash out bugs early in the development cycle and saves a lot of developer time. Continuous Integration (CI) is a development practice that requires developers to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early. There are a lot of tools available that can help you with continuous integration of iOS apps like Xcode Server, Jenkins and Travis CI. Continuous Delivery (CD) is a software engineering approach in which teams produce software in short cycles, ensuring that the software can be reliably released at any time. It aims at building, testing, and releasing software faster and more frequently. Why use Continuous Delivery? 1.Save days of preparing app submission, uploading screenshots and releasing the app 2.Colleague on vacation and a critical bugfix needs to be released? Don’t rely on one person releasing updates 3. Increase software quality and reaction time with more frequent and smaller releases