Slide 1

Slide 1 text

iOS App Development

Slide 2

Slide 2 text

Different Approaches Swift / Objective-C UIKit + Storyboard UIKit + Just Code (Snapkit /Purelayout) SwiftUI Swift Learn the language first! UIKit + XIBs

Slide 3

Slide 3 text

UIKit + Storyboards / XIB • Autolayout can be frustrating • Version control can be cumbersome • Debug can be hard • Use several storyboards! Split your app. • Good approach for small apps • Number of developers... 1?

Slide 4

Slide 4 text

UIKit + Code Everything • "Full control of everything" • Use libraries like snapkit or purelayout for easier coding • Good approach if you want control every aspect • But this will require lot of coding!

Slide 5

Slide 5 text

SwiftUI • The future of Apple Devices development • It's cross platform! The UI code should be reusable on all devices. • No backward compatibility (only iOS 13 +) • Hot Reload can be frustrating • Much less documentation available • Good approach to new apps • Way easier than storyboards

Slide 6

Slide 6 text

Life Cycle and States

Slide 7

Slide 7 text

Storyboard + UIKit App Delegate

Slide 8

Slide 8 text

https://www.business2community.com/mobile-apps/what-you-need-to-know-about-the-new-ios-13-ipad-changes-dark-mode-02251390

Slide 9

Slide 9 text

AppDelegate and SceneDelegate?

Slide 10

Slide 10 text

Info.plist Say Yes to iPad and MacOS!

Slide 11

Slide 11 text

You can add multiple scenes Two different scene configurations

Slide 12

Slide 12 text

AppDelegate vs SceneDelegate – iOS13 • App Delegate manages your app process • Configure your initial scenes • Process events and lifecycle • Scene Delegate manages one instance of your app's user interface • So if the user has created two windows showing your app, you have two scenes, both backed by the same app delegate • Your app no longer moves to background, scenes do! • UI events and lifecycle

Slide 13

Slide 13 text

AppDelegate • Main entry point for your application • Several application level lifecycle events • AppDelegate role has changed from iOS 12 -> 13 • In the default template you will find three (3) methods • Whan app is opened • application(_:didFinishLaunchingWithOptions:) • When creating new scenes (it's basically a window) • Discards a scene • Notice that in addition to these, there are other lifecycle events (when app terminates for example)

Slide 14

Slide 14 text

@main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { NSLog("AppDelegate: First launch") return true } func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { NSLog("AppDelegate: New Scene created") return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { NSLog("AppDelegate: Scene discarded") } } Generates trivial main function that starts the app

Slide 15

Slide 15 text

@main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { NSLog("AppDelegate: First launch") return true } func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { NSLog("AppDelegate: New Scene created") return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { NSLog("AppDelegate: Scene discarded") } } First launch

Slide 16

Slide 16 text

Scene • App can have more than one scene • Allows to build multi-window apps on iOS and iPadOS • App Delegate has functions related to the management of scene sessions • application(_:configurationForConnecting:options:) • Needs a return configuration object when creating a new scene • Can be used to restore the state of a scene • application(_:didDiscardSceneSessions:) • Called when app's user closed one or more scene via the app switcher (according to the doc)

Slide 17

Slide 17 text

@main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { NSLog("AppDelegate: First launch") return true } func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { NSLog("AppDelegate: New Scene created") return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { NSLog("AppDelegate: Scene discarded") } } when new scenes are created. Returns configuration object that hold information which storyboard to use (info.plist). You can decide which configuration to use. When the user removes a scene from the app switcher. If your app is not running, UIKit calls this method the next time your app launches.

Slide 18

Slide 18 text

SceneDelegate import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? Everything seen to the end user is put into a window object

Slide 19

Slide 19 text

import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { NSLog("Creates Window object") guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { NSLog("Scene disconnected!") } func sceneDidBecomeActive(_ scene: UIScene) { NSLog("Active!") } func sceneWillResignActive(_ scene: UIScene) { NSLog("From foreground to background") } func sceneWillEnterForeground(_ scene: UIScene) { NSLog("Will enter foreground") } func sceneDidEnterBackground(_ scene: UIScene) { NSLog("Did enter background") } }

Slide 20

Slide 20 text

Lab

Slide 21

Slide 21 text

Concepts • Window - UIWindow • Basic container for application's views. Window's view is the visible part in the screen. • To add something to the screen, it's done using the UIWindow object. • View - UIView • Define a portion of a window that fills some content. Can be image, text or shape. • UIKit provides predefined views that you can use: UIButton, UILabel etc. • View can be a container for other views • View Controller - UIViewController • Class that acts controller between the model and view

Slide 22

Slide 22 text

"Architecture" UIWindow rootViewController UIViewController view xib file

Slide 23

Slide 23 text

Window • Window (UIWindow) handles the overall presentation of your app's user interface • Windows work with views (usually through view controllers) • After window is created, it stays the same and only the views displayed by it change • Every iOS app has at least one Window • If need for an external display (for example Apple TV) then another Window object is used. • To display a view in window, add the view as an subview of window!

Slide 24

Slide 24 text

View • Building blocks for the UI • View is an instance of UIView (or one of it's subclasses) • Responsible for • drawing content • handling touch events • managing layout for subviews • Parent view (superview) is responsible for positioning and sizing their child views (subviews) • Changing the superview you may influence the subviews, position for example

Slide 25

Slide 25 text

Creating UIWindow class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.backgroundColor = UIColor.yellow self.window = window window.makeKeyAndVisible() } }

Slide 26

Slide 26 text

Creating UIView // Let's define position and size for label let frame = CGRect(x: 0, y: 0, width: 100, height: 100) // Create label let label = UILabel(frame: frame) label.text = "hello" label.backgroundColor = UIColor.darkGray label.textColor = UIColor.white

Slide 27

Slide 27 text

Creating UIViewController let viewController = UIViewController() viewController.view.addSubview(label) window.rootViewController = viewController

Slide 28

Slide 28 text

Setting up Window: Just Code if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.backgroundColor = UIColor.yellow // Let's define position and size for label let frame = CGRect(x: 0, y: 0, width: 100, height: 100) // Create label let label = UILabel(frame: frame) label.text = "hello" label.backgroundColor = UIColor.darkGray label.textColor = UIColor.white let viewController = UIViewController() viewController.view.addSubview(label) window.rootViewController = viewController self.window = window window.makeKeyAndVisible() }

Slide 29

Slide 29 text

Lab

Slide 30

Slide 30 text

Interface Builder

Slide 31

Slide 31 text

About View Controllers • View Controllers are a link between app's data and visual appearance • Displayed content should go always through a view controller (content view controller) • When implementing iOS app you have multiple view controller's for each screen. • View Controller can be also a container view controller • A view controller holding other view controllers! • Several built-in content view controllers available, like navigation or tab view controller

Slide 32

Slide 32 text

View Controllers, Xib, Storyboard? • We built our app using Model – View – Controller • Model -> Holds data of your app • View -> either .xib or .storyboard • Controller -> controls the model and the view • When creating a new "screen" to our app, you typically have 1.Controller class 2.View either in .xib or in .storyboard 28.10.2020 ESITYKSEN NIMI / TEKIJÄ 32

Slide 33

Slide 33 text

Word about Storyboards • Storyboard is a feature in iOS 5 -> where you can design and build a UI for your apps. • One file may contain several screens! • Good • Better overview of all the screens in your app • Describes transitions between screens, simply ctrl-drag from screen to another to create "segue" • Storyboards are nice for apps with small or medium number of screens • Bad • Storyboard will get very confusing if you have lot of screens. • You need a big screen • Apple seems to be pushing the storyboard approach • Apple seems to be pushing towards SwiftUI

Slide 34

Slide 34 text

View Controller manages Views • Each View Controller organizes and controls it's view. • The view is often a "root view" containing other views • View Controller is usually your own class, extending UIViewController • When setting some view controller as a rootViewController of the UIWindow, then window will automatically add the view controller's view to subview (and visible to screen.) • When you have storyboard declared in info.plist 1. main.storyboard file is opened 2. it's initial view controller is set as root view controller 3. root view controllers view is added to window

Slide 35

Slide 35 text

Implementing a View Controller • To implement a view controller, you subclass UIViewController • The View Controller controls all the views in that "screen" • View Controller usually responds to user events happening to those views • Button presses, touches and so on • Usually the views are designed using Interface builder.

Slide 36

Slide 36 text

Overriding methods • You can override UIViewController's methods • viewDidLoad • allocate and load data to be displayed in view • viewDidAppear • when view is visible • viewDidDisappear • when view is not visible • didReceiveMemoryWarning • Respond to low memory notifications

Slide 37

Slide 37 text

Storyboard • Storyboard holds visual presentation of all your views and view controllers • When creating your template app, you have storyboard holding your view controller and view. • From identity inspector you can see that the view controller is linked to a file called ViewController.swift • From attributes inspector you can simulate different screen sizes

Slide 38

Slide 38 text

Outlet: Connect from Code to View • Outlet is a variable that is annotated with the symbol IBOutlet • The value of the outlet is specified graphically in a storyboard • Example: declare a UILabel as an outlet • @IBOutlet weak var myButton: UIButton! • Drag UIButton to Storyboard and ctrl-drag to ViewController - code Demo

Slide 39

Slide 39 text

Target-Action • Target Action is a design pattern in an object holds information necessary to send to another object when an event occurs. • "Which method is called when button is clicked?" • An action method must have a certain form: • @IBAction func buttonClicked(sender: AnyObject) {..} • You can set target and action in code or using Interface Builder Demo

Slide 40

Slide 40 text

Auto Layout • Auto Layout is a system that let's you lay out app's UI elements creating relationships between elements • These relationships are called constraints • You can create constraints to an element or a group of elements • Basic idea is to create UI that works on different screen sizes and orientation 28.10.2020 ESITYKSEN NIMI / TEKIJÄ 40

Slide 41

Slide 41 text

Constraint • Fundamental building block in auto layout is Constraint • Rules about how to layout elements • Examples • specify element width • specify horizontal distance from another element • Auto Layout calculates all constraints at the same time and tries to layout your UI 28.10.2020 ESITYKSEN NIMI / TEKIJÄ 41

Slide 42

Slide 42 text

Working with Constraints • You can add constraints in several ways • Control-drag • Drag from view to view and select the constraint you want to use • Align and Pin Menus • On the bottom of the canvas, you can see a small icon group. Select either align or pin 28.10.2020 ESITYKSEN NIMI / TEKIJÄ 42

Slide 43

Slide 43 text

Building a BMI app Demo

Slide 44

Slide 44 text

Moving Between View Controllers

Slide 45

Slide 45 text

UIWindow • Remember that everything visible in the screen goes through UIWindow • UIWindow has a property rootViewController that provides the content view of the visible window. • You can change this at runtime in view controller • self.view.window?.rootViewController = SecondScreenController(nibName: "SecondScreen", bundle: nil)

Slide 46

Slide 46 text

Container View Controller • Usually we don't just "change screens". • Problem is that we have to define navigation programmatically. How user is coming back? What kind of visual cues are we giving to the user about the navigation? • Instead it's good practice to use container view controllers • Container view controller contains other view controllers • UINavigationController • UITabController • There are couple ready made content view controllers, but you can also build our own.

Slide 47

Slide 47 text

UINavigationController

Slide 48

Slide 48 text

UINavigationController • Navigation Tab Controller implements a specialized view controller that manages the navigation hierarchical content

Slide 49

Slide 49 text

About Navigation Stack • The Navigation controller manages currently displayed screens using a navigation stack • Bottom stack: root view controller • Top of the stack: view controller that is displayed currently • To add a new screen: • pushViewController:animated: • To remove the displayed screen • popViewControllerAnimated: • Navigation controller provides you a back button, that pops the current view

Slide 50

Slide 50 text

Example using the Navigation func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let win = UIWindow(windowScene: scene as! UIWindowScene) let root = FirstScreenController(nibName: "FirstScreen", bundle: nil) root.title = "First screen" let navController = UINavigationController(rootViewController: root) win.rootViewController = navController self.window = win win.makeKeyAndVisible() }

Slide 51

Slide 51 text

Push class FirstScreenController : UIViewController { var secondScreen : SecondScreenController? = nil @IBAction func changeScreen(_ sender: Any) { if self.secondScreen == nil { self.secondScreen = SecondScreenController(nibName: "SecondScreen", bundle: nil) } self.navigationController!.pushViewController(self.secondScreen!, animated: true) } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } }

Slide 52

Slide 52 text

Lazy loading class FirstScreenController : UIViewController { lazy var secondScreen : SecondScreenController = SecondScreenController(nibName: "SecondScreen", bundle: nil) @IBAction func changeScreen(_ sender: Any) { self.navigationController!.pushViewController(self.secondScreen, animated: true) } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } }

Slide 53

Slide 53 text

Using Storyboard • Create your navigation using Interface Builder – no code! • How? • Select your root view controller • Choose Menu: Editor » Embed in » Navigation Controller • Now your view controller is embedded inside of a navigation controller! • Create new view controller to storyboard • Create button to first view controller and ctrl-drag to the new view controller. Choose push and you now have a new navigation from view to another!

Slide 54

Slide 54 text

Segues • Show • Pushes the destination view controller onto the navigation stack, moving the source view controller out of the way providing a back button to navigate back to the source – on all devices • Show Detail • Replaces the detail/secondary view controller when in a UISplitViewController with no ability to navigate back to the previous view controller. Example: Mail in iPad in landscape when tapping mail title. • Present Modally • Presents a view controller in various different ways as defined by the Presentation option, covering up the previous view controller - most commonly used to present a view controller that animates up from the bottom and covers the entire screen on iPhone • Present as popover • When run on iPad, the destination appears in a small popover, and tapping anywhere outside of this popover will dismiss it.

Slide 55

Slide 55 text

Example about Passing Data override func prepare(for _segue: UIStoryboardSegue, sender: Any?) { let destViewController = _segue.destination as! SecondScreenStoryboardController destViewController.stuff = "Some Data For You!" }

Slide 56

Slide 56 text

And receiving data class SecondScreenStoryboardController: UIViewController { var stuff : String = "" override func viewDidLoad() { super.viewDidLoad() self.title = "Second Screen" } override func viewDidAppear(_ animated: Bool) { print(stuff) } }

Slide 57

Slide 57 text

Should Segue open? • If you want to decide if segue should perform, add shouldPerformSegueWithIdentifier - method to your view controller • This method is called before the segue should start. • In the method, return true if you want to open the next View Controller override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { return false }

Slide 58

Slide 58 text

UITabBarController

Slide 59

Slide 59 text

UITabBarController • A tab bar controller is a container view controller that you use to divide your app into two or more distinct modes of operation • Tab bar holds multiple tabs, each represented by a child view controller • Selecting the tab causes the view controller's view to be displayed on the screen

Slide 60

Slide 60 text

Objects of the Tab Bar • Standard Tab Bar interface consists of • UITabBarController object • One content view controller for each tab • Really easy to use • Allocate the UITabController • Use viewControllers property to set the custom view controllers • Add the UITabController to be rootViewController • Or use Storyboard

Slide 61

Slide 61 text

Example let tabs = UITabBarController() let a = Tab1Controller(nibName: "Tab1Controller", bundle: nil) a.title = "First Tab" let b = Tab2Controller(nibName: "Tab2Controller", bundle: nil) b.title = "Second Tab" tabs.viewControllers = [a, b] self.window?.rootViewController = tabs

Slide 62

Slide 62 text

Modifying Tab Title and Image • To set the tab title and image, you do this in your custom view controller • The UIViewController holds a property tabBarItem (UITabBarItem) that you can use to change the current tab bar • The default title of the tab is the title of the view controller. • So changing the title of view controller will influence the tab to have a title also!

Slide 63

Slide 63 text

Mixing Container View Controllers • It's possible to mix container view controllers • For example, tab controller can hold navigation controller

Slide 64

Slide 64 text

Display Data on TableView

Slide 65

Slide 65 text

TableView

Slide 66

Slide 66 text

Classes Needed • Table View • UITableView • Manage selections, scroll the table view, insert or delete rows and selections • UITableView inherites UIScrollView, defines scrolling as default • Table View Controller • UITableViewController • Adds support for many standard table related behaviors. Minimize the amount of code you have to write. • Subclass UITableViewController • Data Source and Delegate • UITableView must have delegate and data source: UITableViewDataSource and UITableViewDelegate

Slide 67

Slide 67 text

UITableViewDelegate • Lot’s of options: • Configuring Rows for the Table View • Managing Selections • Modifying Header and Footer • Editing Table Rows • Clicking a Row • See UITableViewDelegate documentation for all methods, all optional functions

Slide 68

Slide 68 text

UITableViewDelegate: didSelectRowAt override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("section: \(indexPath.section)") print("row: \(indexPath.row)") }

Slide 69

Slide 69 text

Without UITableViewController class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var dummyData = ["Luke Skywalker", "R2-D2"] @IBOutlet weak var tableview: UITableView! override func viewDidLoad() { super.viewDidLoad() self.tableview.delegate = self self.tableview.dataSource = self } ... } This data will be displayed tableview is in xib let's pass delegate and datasource as self. This class must conform to the protocols

Slide 70

Slide 70 text

Data Source functions func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dummyData.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell : UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "mickeymouse") if cell == nil { cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "mickeymouse") } cell?.textLabel?.text = dummyData[indexPath.row] return cell! } Number of rows Must return UITableViewCell. The text is fetch from the array. Reuses cell objects

Slide 71

Slide 71 text

UITableViewController class MyTableViewController2: UITableViewController { var dummyData = ["Luke Skywalker", "R2-D2"] override func viewDidLoad() { super.viewDidLoad() } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dummyData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell : UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "mickeymouse") if cell == nil { cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "mickeymouse") } cell?.textLabel?.text = dummyData[indexPath.row] return cell! } } conforms to the protocols, sets the delegate and datasource. Has tableView property If we want we can create the cell also in interface builder

Slide 72

Slide 72 text

mycell.xib Drag Table Cell View Specify reuse identifier

Slide 73

Slide 73 text

Usage class MyTableViewController2: UITableViewController { var dummyData = ["Luke Skywalker", "R2-D2"] override func viewDidLoad() { super.viewDidLoad() let xibfile = UINib(nibName: "mycell", bundle: nil) self.tableView.register(xibfile, forCellReuseIdentifier: "mikkihiiri") } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dummyData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let secondCell = tableView.dequeueReusableCell(withIdentifier: "mikkihiiri")! secondCell.textLabel?.text = dummyData[indexPath.row] return secondCell } } Register the separate xib file And then we can just use it without if ...

Slide 74

Slide 74 text

Storyboard By using storyboard you will have the cell xib embedded here. No need for external xibs

Slide 75

Slide 75 text

Connecting to Backend (Swift)

Slide 76

Slide 76 text

URLSession • For simple requests, use URLSession.shared object • When receiving stuff, you will get NSData object • It is asynchronous • The URLSession.shared has method func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

Slide 77

Slide 77 text

Example let myURL = URL(string: "https://pohjus-rest-location.herokuapp.com/locations")! let httpTask = URLSession.shared.dataTask(with: myURL) { (optionalData, response, error) in print("done fetching") } httpTask.resume()

Slide 78

Slide 78 text

Example let myURL = URL(string: "https://pohjus-rest-location.herokuapp.com/locations")! let httpTask = URLSession.shared.dataTask(with: myURL) { (optionalData, response, error) in print("done fetching") } httpTask.resume() NSData? URLResponse? Error?

Slide 79

Slide 79 text

Example: Using Response let httpTask = URLSession.shared.dataTask(with: myURL) {(optionalData, response, error) in if let httpResponse = response as? HTTPURLResponse { print("statusCode: \(httpResponse.statusCode)") } } HTTPURLResponse is a subclass of URLResponse

Slide 80

Slide 80 text

Example: Data -> String let httpTask = URLSession.shared.dataTask(with: myURL) {(optionalData, response, error) in let data : String = String(data: optionalData!, encoding: .utf8)! print(data) }

Slide 81

Slide 81 text

With View Controller override func viewDidAppear(_ animated: Bool) { self.fetch(url: "https://pohjus-rest-location.herokuapp.com/locations") } func fetch(url: String) { let myURL = URL(string: url)! let httpTask = URLSession.shared.dataTask(with: myURL) { (optionalData, response, error) in self.parse(data: optionalData) } httpTask.resume() } func parse(data: Data?) { if let d = data { print(String(data: d, encoding: String.Encoding.utf8)!) } } When view appears start fetching When view appears start fetching and call parse Outputs data as String

Slide 82

Slide 82 text

Parsing JSON (Swift)

Slide 83

Slide 83 text

Location struct Location: Decodable { let lat: Double let lon: Double }

Slide 84

Slide 84 text

Example let jsonDecoder = JSONDecoder() do { let stuff = try jsonDecoder.decode(Array.self, from: optionalData!) print(stuff) } catch let error { print(error) } Custom struct, must conform to Codeable

Slide 85

Slide 85 text

Example override func viewDidAppear(_ animated: Bool) { self.fetch(url: "https://pohjus-rest-location.herokuapp.com/locations") } func parse(data: Data?) { if let d = data { let jsonDecoder = JSONDecoder() do { let stuff = try jsonDecoder.decode(Array.self, from: d) print(stuff) } catch let error { print(error) } } } func fetch(url: String) { let myURL = URL(string: url)! let httpTask = URLSession.shared.dataTask(with: myURL) { (optionalData, response, error) in self.parse(data: optionalData) } httpTask.resume() } Now we have an array full of location objects

Slide 86

Slide 86 text

Threading • it's never OK to do user interface work on the background thread. • If you're on a background thread and want to execute code on the main thread • DispatchQueue.main.async { UI STUFF HERE }

Slide 87

Slide 87 text

class MyTableViewController2: UITableViewController { var dummyData : Array = [] override func viewDidLoad() { super.viewDidLoad() let xibfile = UINib(nibName: "mycell", bundle: nil) self.tableView.register(xibfile, forCellReuseIdentifier: "mikkihiiri") } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dummyData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let secondCell = tableView.dequeueReusableCell(withIdentifier: "mikkihiiri")! secondCell.textLabel?.text = "\(dummyData[indexPath.row].lat) - \(dummyData[indexPath.row].lon)" return secondCell } override func viewDidAppear(_ animated: Bool) { self.fetch(url: "https://pohjus-rest-location.herokuapp.com/locations") } func parse(data: Data?) { if let d = data { let jsonDecoder = JSONDecoder() do { let stuff = try jsonDecoder.decode(Array.self, from: d) self.dummyData = stuff DispatchQueue.main.async { self.tableView.reloadData() } } catch let error { print(error) } } } func fetch(url: String) { let myURL = URL(string: url)! let httpTask = URLSession.shared.dataTask(with: myURL) { (optionalData, response, error) in self.parse(data: optionalData) } httpTask.resume() } }