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

Daniel Burke: Scratch that: Building an app in Swift

Realm
March 01, 2017

Daniel Burke: Scratch that: Building an app in Swift

Video: https://www.youtube.com/watch?v=HtBSvPFaCWE&feature=youtu.be

Title: Scratch that: Building an app in Swift

Speaker: Daniel Burke is a Software Engineer at Yelp building the next phase of Yelp's messaging platform. Before this, Daniel managed a team of iOS & Android developers at ForRent.com in Norfolk, VA as well as a team of R&D developers focused on leveraging new and emerging technologies. Before DE, Daniel was a web and iOS developer at Grow in Norfolk, VA, working with companies like Google, Burberry, and RedBull. Daniel is a leading member of ColorCoded, a group within Yelp focused on fostering diversity in the engineering community through mentorship, workshops, and public speaking. Daniel enjoys basketball, running, hiking, scuba-diving, and skiing and is the proud father of a 4-year-old daughter and a 10-year-old son.

Abstract: There are plenty of reasons why you may be considering Swift for your next project. You may be starting a new venture, rebuilding an existing app, learning Swift as a new language, or even just beginning your adventure as a programmer. Let's talk about these scenarios and learn by doing. In this talk/workshop, we'll build the core features of a basic app and cover the most important elements of building an iOS app in Swift from scratch. Bring your Mac with the latest version of Xcode installed and be ready for fast paced instruction and witty banter.

Twitter Link: https://twitter.com/d2burke

Realm

March 01, 2017
Tweet

More Decks by Realm

Other Decks in Technology

Transcript

  1. • Intro *Lite • Setting up • Building the app

    • Optimizations (Maybe?) Agenda
  2. • Software Engineer @ Yelp ◦ Messaging ◦ Current: Obj-C

    -> Swift • Eng. Mgr @ForRent.com ◦ Framework -> Swift ◦ Swift -> Obj-C ◦ Swift From Scratch Me Daniel Burke
  3. • How many have shipped an app as the primary

    or only engineer? • How many have shipped an app as a part of a team? • How many of you are new to programming within the last year? You The Audience
  4. • New Project • Single View Application • Name: “Matchup”

    • Language: Swift • Git: Absolutely Setting up Xcode
  5. • Project Navigator (File Structure) ◦ ** delete ViewController [“Move

    to Trash”] • Debug Area (Console) • Utilities (Inspectors & Attributes) Setting up Xcode
  6. • By Class Type (MVC, Utils) • By Feature/Team (Feature,

    Auth Flow) • Favor new files Setting up File Structure
  7. • Use branches • Commit early and often • Push

    complete features Setting up Version Control
  8. • Don’t reinvent the wheel • Carefully vet 3rd party

    libraries • Pay respects via attribution if you ship Setting up Dependencies
  9. $ vim Podfile --- source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks!

    target 'Matchup' do pod 'AlamofireImage', '~> 3.1' end --- $ pod install Analyzing dependencies Downloading dependencies Using Alamofire (4.3.0) ... Close Xcode Open *.xcworkspace
  10. • Player List (type inferencing, self-invoking closures, extensions, guard) •

    Matchup Results (custom init(), string interpolation) • Login View (storyboard layouts, protocols) Building the app
  11. • Add some views • Install some AL constraints •

    Wire up our TableView • Wire up our Compare button Building the app Player List
  12. ** Create Controller/PlayersViewController.swift // 1. In AppDelegate.swift > application:didFinishLaunching... let

    playersViewController: PlayersViewController() playersViewController.view.backgroundColor = .white let navController = UINavigationController(rootViewController.. navController.navigationBar.isTranslucent = false window?.rootViewController = navConroller window?.makeKeyAndVisible() Set up initial view Player List
  13. // 1. Add button and function lazy var compareButton: UIButton

    = {... // 2. var disabledGray = UIColor.lightGray.withAlphaComponent(0.5) ** Can’t access `self` until it has been initialized ** Here we can use a lazy var - waits until var is accessed :) Add some views Player List
  14. // 3. var playerTableView: UITableView = {... // 4. Add

    views and set delegate view.addSubview(playerTableView) … ** The compiler is going to be annoying until we fully conform to the UITableView delegate, so do let’s ** Create Model/Player.swift Copy Pasta: http://pastebin.com/hTXZ3p10 Add some views (cont’d) Player List
  15. // 1. func installConstraints() { // 2. let views:[String:UIView]=[“compareButton”:compareButton… compareButton.translatesAutoresizingMask…

    let constraints = [NSLayoutConstraint.constraints… NSLayoutConstraint.activate(constraints.flatMap({ $0 })) } // 3. installConstraints() Add some constraints Player List Build (and run) CMD + R
  16. ** Create a Set to hold our selected cell indexPaths

    var checkedCells = Set<IndexPath>() // 1. Get player for cell let player = Player(dict: players[indexPath.row]) // 2. Configure our cell cell.textLabel?.text = player?.name... if checkedCells.count == 2 { cell.isUserInteractionEnabled = (isSelected) ? true : ... cell.textLabel?.textColor = (isSelected) ? .black : ... Configure our TableView cells Player List
  17. // 1. extension SearchViewController: UITableViewDelegate { func tableView(_ tableView: UITableView,

    didSelectRowAt... if checkedCells.contains(indexPath) {... // 2. let color: UIColor = (checkedCells.count == 2) ? .white... let backgroundColor = (checkedCells.count == 2) ? .blue... compareButton.backgroundColor = backgroundColor ... //3. playerTableView.reloadData() Handle selecting players Player List Build (and run) CMD + R
  18. func didTapCompareButton(button: UIButton) { // 1. Cast Set to Array

    let indexPaths = Array(checkedCells) // 2. Validate guard checkedCells.count == 2, let indexPath1 = indexPaths.first, let indexPath2 = indexPaths.last, let player1 = Player(dict: players[indexPath1.row]), let player2 = Player(dict: players[indexPath2.row]) else { return } ... Compare Players Func Player List
  19. ** Create Controller/MatchupViewController.swift view.backgroundColor = .white // 1. Add player

    vars let player1: Player let player2: Player // 2. Add custom init() init(player1: Player, player2: Player) { self.player1 = player1 self.player2 = player2 super.init(nibName: nil, bundle: nil) ... Set up match-up view Matchup View
  20. ** Back in Controller/PlayersViewController.swift // 3. Create Matchup View with

    custom init() let matchupView = MatchupViewController( player1: player1, player2: player2 ) // 4. Push view onto the stack self.navigationController?.pushViewController(matchupView… ** Compare Players Func (cont’d) Player List Build (and run) CMD + R
  21. ** Back in Controller/MatchupViewController.swift // 1. Add name labels let

    player1Label: UILabel = { ... let player2Label: UILabel = { ... // 2. Update our title let player1Wins = player1.rating > player2.rating let winnerName = player1Wins ? player1.name : player2.name title = "\(winnerName) Wins!" Copy Pasta: http://pastebin.com/BhD6G8Vh Add some views Matchup View
  22. ** Create View/UIImageView+Loader.swift // 1. Load image asynchronously Copy Pasta:

    http://pastebin.com/sxhst8R8 Load some images Matchup View
  23. // 1. Set image with result of async call ...

    if let image = response.result.value { self.image = image } ... Load some images (cont’d) Matchup View
  24. // 2. Call this function on our images override func

    viewWillAppear(_ animated: Bool) { player1ImageView.loadImage(imageURL: player1.imageURL) player2ImageView.loadImage(imageURL: player2.imageURL) } Load some images (cont’d) Matchup View Build (and run) CMD + R
  25. • Player List (type inferencing, self-invoking closures, extensions, guard) •

    Matchup Results (custom init(), string interpolation) • Login View (storyboard layouts, protocols) Building the app
  26. ** Drag out a UIView, 2 UIButtons, & UITextField Set

    up login view (cont’d) Log In View
  27. // 1. Create delegate protocol LoginViewControllerDelegate { func didLogin() }

    ... // 2. Call delegate method @IBAction func login(_ sender: Any) { delegate?.didLogin() } Set up login view (cont’d) Log In View
  28. ** Back in Controller/PlayersViewController.swift // 3. Conform to LoginViewControllerDelegate extension

    PlayersViewController: LoginViewControllerDelegate { func didLogin() { UserDefaults.standard.set("yes", forKey: "LoggedIn") dismiss(animated: true, completion: nil) } } Set up login view (cont’d) Log In View
  29. ** Back in Controller/PlayersViewController.swift // 4. In viewWillAppear: guard let

    _ = UserDefaults.standard.object(forKey: "LoggedIn") else { presentLogin() } Copy Pasta: http://pastebin.com/vTmAUhi5 Set up login view (cont’d) Log In View Build (and run) CMD + R
  30. ** Back in Controller/PlayersViewController.swift // BONUS. Add a Log Out

    button navigationItem.rightBarButtonItem = UIBarButtonItem(title:... // 5. Add logOut func func logOut() { UserDefaults.standard.remove(forKey: "LoggedIn") presentLogin() } Set up login view (cont’d) Log In View
  31. • Configuring views with ViewModels (buttons, cells, fields, etc) •

    Moving Delegate/Datasource code to separate files Optimizations