Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Julián Gutiérrez - Long Lasting iOS Projects

Julián Gutiérrez - Long Lasting iOS Projects

While we all love to speak about Swift 3+, Reactive code and all the new shiny stuff out there, we also need to think on what makes a project last. We will explore some of my experiences developing single app projects vs a mobile platform with a 5 year old codebase. What made it survive and what mistakes were made that can be considered for even your own project! As a bonus we will talk about how to make consistent and fast builds (i.e if you're currently exporting from Xcode and uploading to iTunes connect, there's better ways of doing it!)

Presentation from the July 2017 iOSoho Meetup: https://www.meetup.com/iOSoho/events/235600015

iOSoho

July 10, 2017
Tweet

More Decks by iOSoho

Other Decks in Programming

Transcript

  1. ‘07 ‘08 ‘09 ‘10 ‘11 ‘12 ‘13 ‘14 ‘15 ‘16

    ‘17 January 9 It’s been a fast decade
  2. Pros & Cons • Clean Slate • Ability to experiment

    different architectures & patterns • Easier to apply lessons from mistakes made in the past • Little or no reusability • Ramp-up time is higher for every project • Cost and resources need to be higher
  3. Objective-C 1.0 ‘07 ‘08 ‘09 ‘10 ‘11 ‘12 ‘13 ‘14

    ‘15 ‘16 ‘17 @implementation MyDasource - (id) init { self = [super init]; if (self) { datasource = [[self buildDatasource] retain]; } return self; } -(NSDictionary *) buildDatasource { NSArray *objects = [NSArray arrayWithObjects:@"Hello World!", nil]; NSArray *keys = [NSArray arrayWithObjects:@"message", nil]; NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString * currentKey; for(int i = 0; i< [keys count]; i++) { currentKey = [keys objectAtIndex:i]; NSLog(@"Value = %@", [dictionary valueForKey:currentKey]); } return dictionary; } @end Xcode 3.0 October 26
  4. Objective-C 2.0 ‘07 ‘08 ‘09 ‘10 ‘11 ‘12 ‘13 ‘14

    ‘15 ‘16 ‘17 @implementation MyDasource - (id) init { self = [super init]; if (self) { datasource = [[self buildDatasource] retain]; } return self; } -(NSDictionary *) buildDatasource { NSDictionary * dictionary = @{//Uses in-line literal @"message": @"Hello World, Again!" }; for (NSString * currentKey in dictionary) { //fast enumeration NSLog(@"Value2 = %@", dictionary[currentKey]);//subscript accessing } return dictionary; } @end Xcode 3.1-4.1.1 August 2
  5. ARC Migration ‘07 ‘08 ‘09 ‘10 ‘11 ‘12 ‘13 ‘14

    ‘15 ‘16 ‘17 Xcode 4.2 October 12 @implementation MyDasource - (id) init { self = [super init]; if (self) { datasource = [self buildDatasource]; //ARC Increases retain count +1 when assigning to iVars } return self; } -(NSDictionary *) buildDatasource { NSDictionary * dictionary = @{ @"message": @"Hello World, Again!" }; for (NSString * currentKey in dictionary) { NSLog(@"Value2 = %@", dictionary[currentKey]); } return dictionary; } @end
  6. iOS 8's new Coordinate system ‘07 ‘08 ‘09 ‘10 ‘11

    ‘12 ‘13 ‘14 ‘15 ‘16 ‘17 September 17 Xcode 6.1 1.0 @interface ESViewController : UIViewController @end @implementation ESViewController - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } //whoops... deprecated method - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if (interfaceOrientation == UIInterfaceOrientationPortrait) { // some logic } return YES; } //easy fix.. when wrapping external code - (BOOL)shouldAutorotate { UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation]; return [self shouldAutorotateToInterfaceOrientation: orientation]; } @end
  7. Nullability ‘07 ‘08 ‘09 ‘10 ‘11 ‘12 ‘13 ‘14 ‘15

    ‘16 ‘17 Xcode 6.3 1.2 @implementation MyDasource //... NS_ASSUME_NONNULL_BEGIN -(NSDictionary *) buildDatasource { NSDictionary * dictionary = @{ @"message": @"Hello World, Again!" }; for (NSString * currentKey in dictionary) { NSLog(@"Value2 = %@", dictionary[currentKey]); } return dictionary; } //... -(NSString *) stringForKey:(NSString *)aKey{ NSString * key = datasource[aKey]; return key ? key: @""; } NS_ASSUME_NONNULL_END @end April 8
  8. Bridging to Swift 3.0 ‘07 ‘08 ‘09 ‘10 ‘11 ‘12

    ‘13 ‘14 ‘15 ‘16 ‘17 Xcode 8.0 3.0 class SwiftViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.testBridging() } func testBridging(){ let datasource = MyDatasource.init() let message : String! = datasource.string(forKey:"message") print("The message is", message) } } June 13 @implementation MyDasource //... NS_ASSUME_NONNULL_BEGIN //... -(NSString *) stringForKey:(NSString *)aKey{ NSString * key = datasource[aKey]; return key ? key: @""; } NS_ASSUME_NONNULL_END @end
  9. Don’t abuse libraries • If you just need a small

    piece of functionality try to implement it yourself. • Library maintainers might not be as fast as you need them to be or might move on to something else, leaving you with a liability. • Every line of code that is part of your project is a line you commit to maintain.
  10. Wrap third party libraries • Single point of communication, one

    place to fix/maintain if requirements change. • This is a (failed) wrapper:
  11. Don't let your classes know more than they should. •

    Ask your class: what do you do? ✓ESNetworkRequest ✴AppResource “If you can't describe what your class does in one line and without using AND you probably need to break it up.” ~Robert Martin, Clean Code
  12. Code Analysis $ curl -sL bit.ly/codeDistribution | sh Distribution of

    Code Lines AlamoFire (1) 43 Files EachScape (2) 518 Files RxSwift (3) 939 Files AFNetworking (4) 81 Files
  13. • Avoid third party libraries whenever possible. • Add layers

    between your code and external libraries (single point of communication) • Even UIKit and Apple frameworks are code you don't control! So don't take things for granted. • As you pass by files you don't frequent, check for code style, smelly code and clean it up! Conclusions