Improving your Existing Apps with Swift - Apple Inc. · What’s new in Swift Presidio Tuesday...

Post on 19-Jul-2020

3 views 0 download

Transcript of Improving your Existing Apps with Swift - Apple Inc. · What’s new in Swift Presidio Tuesday...

© 2015 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Improving your Existing Apps with SwiftGetting Swifty with It

Woody L. 🐳 in the Sea of Swift

Developer Tools #WWDC15

Session 403

DemoSet the Time Machine to 2012

The Elements has been restored from a vault

Agenda

The “before” appModernizing UIMix and matchSwift StructsAvailabilityLive filtering

Modernizing UI

Walk. Walk. Fashion, Baby.

Tile Sizes

Small Tile Detail Tile

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Pre-Rendered Backgrounds

256px

37px

Pre-Rendered Backgrounds

37px

256px

256px = 256pt @ 1x 512px = 256pt @ 2x 768px = 256pt @ 3x

256px = 256pt @ 1x 512px = 256pt @ 2x 768px = 256pt @ 3x

Does Not Exist

Does Not Exist

ArgonAtomic Weight: 39.95

State: GasPeriod: 3Group: 18

ArgonAtomic Weight: 39.95

State: GasPeriod: 3Group: 18

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Tile Appearance

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Tile Appearance

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Tile Appearance

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Benefits of Custom Drawing Code

Goals Custom Drawing Code

Modernize the Look

Crisp, Sharp Corners

Resolution Independence

Mix and MatchExtending Objective-C Classes with Swift

An interoperability overture in the key of Swift.

Class DesignBase Class

Class Definition

Base

Class DesignBase Class + Category

Class Definition

Base Category

Class DesignBase Class + Categories

Class Definition

Base Category Category Category Category Category

Class DesignBase Class + Categories

Class Definition

Category Category Category Category CategoryBase

Class DesignBase Class + Categories + Swift Extensions

Class Definition

Extension Category Category Category CategoryBase

Class DesignBase Class + Categories

Class Definition

Base Extension Category CategoryExtension Extension

Class DesignMixed-Language Classes

Bridging Header

Generated Header

Base Extension

Class DesignMixed-Language Classes

Generated Header

Created by Compiler

Maintained by Compiler

#import “Product-Swift.h” into MyClass.m

Exists in DerrivedData

Bridging Header

Created by Xcode

Maintained by you

Contains #import “MyClass.h”

Exists in File Navigator

DemoModernizing The Elements UI

Boasting 120% daily intake of vitamin Swift.

Partially Rounded Corners

Partially Rounded Corners

Swift StructsWith Playground prototyping

Global utility functions: shake ‘em off.

Bezier Path

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Bounding Rectangle

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Draw StrokeStroke’s midpoint is the Bezier Path

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Draw StrokeStroke’s midpoint is the Bezier Path

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Draw StrokeClipping

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Draw StrokeClipping

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

SolutionInset the Bezier Path

18 ArArgon

Atomic Weight: 39.95State: GasPeriod: 3Group: 18

Discovered: 1849 A.D.

Utility FunctionsCore Graphics API

Global Utility FunctionsStruct

CGRect

CGRectZero() CGRectMake()

CGRectGetMaxY() CGRectGetWidth()

CGRectUnion() CGRectInset()

Utility FunctionsCore Graphics API

CGRect

CGRectZero() CGRectMake()

CGRectGetMaxY() CGRectGetWidth()

CGRectUnion() CGRectInset()

MethodsStruct

Utility FunctionsCore Graphics API

.zeroRect (x:,y:,w:,h:)

.maxY

.width .union(r)

.rectByInsetting(dx:,dy:)

CGRect

Initializers + MethodsStruct

Utility FunctionsCore Graphics API

Consistent

Initializer Syntax

Encapsulation

Code Completion

API Discovery

.zeroRect (x:,y:,w:,h:)

.maxY

.width .union(r)

.rectByInsetting(dx:,dy:)

CGRect

Initializers + MethodsStruct

Playgrounds for PrototypingTweak-build loop

Build / Compile

Copy into Simulator

Navigate to UI

Check Work

Commit Tweak Code

Playgrounds for PrototypingTweak-build loop

Build / Compile

Copy into Simulator

Navigate to UI

Check Work

Commit Tweak Code

Risk of DestabilizingKnown-Good Code

Slow

Playgrounds for PrototypingThe plan

Check Work

Tweak Code• Reduce Roundtrip Time• Iterative + Experimental Development

Reduce roundtrip timeIterative + experimental development

DemoStruct Methods

With Playground Prototyping

Availability: the Next Generation

Put down your if respondsToSelector() and step away from Xcode.

Runtime InterrogationThe classic way

if ([UIImagePickerController instancesRespondToSelector: @selector(availableCaptureModesForCameraDevice:)]) { // Method is available for use. } else { // Method is not available. }

Availability Based on OS VersionThe officially endorsed, modern way

if #available(iOS 8.3, *) { viewController.modalPresentationStyle = .Popover if let popoverPC = viewController.popoverPresentationController { let cell = tableView.cellForRowAtIndexPath(indexPath) popoverPC.sourceView = cell popoverPC.delegate = self } presentViewController(viewController, animated: true, completion: nil) } else { // Earlier than iOS 8.3 APIs navigationController?.pushViewController(viewController, animated: true) }

Compile-Time Availability Checking

viewController.modalPresentationStyle = .Popover if let popoverPC = viewController.popoverPresentationController { let cell = tableView.cellForRowAtIndexPath(indexPath) popoverPC.sourceView = cell popoverPC.delegate = self }

Compile-Time Availability Checking

viewController.modalPresentationStyle = .Popover if let popoverPC = viewController.popoverPresentationController { let cell = tableView.cellForRowAtIndexPath(indexPath) popoverPC.sourceView = cell popoverPC.delegate = self }

error: ‘popoverPresentationController’ is only available on iOS 8.0 or newer

DemoAvailability

APIs must be this tall to ride.

Availability

New in Swift 2Compilation-time checking of API AvailabilityRuntime checks inserted automatically

Swift in Practice Presidio Thursday 2:30PM

Live Search

Filtering elements since antiquity.

FeIRONNa

SODIUMCs

CESIUMNiNICKELCuCOPPER

ContentView Controller

TableView

FeIRON

NaSODIUM

CsCESIUM

NiNICKEL

CuCOPPER

TableView

Content

View Controller<UITableViewDataSource>

TableView

Content FeIRON

NaSODIUM

CsCESIUM

NiNICKEL

CuCOPPER

View Controller<UITableViewDataSource, UISearchBarDelegate>

TableView

Content FeIRON

NaSODIUM

CsCESIUM

NiNICKEL

CuCOPPER

View Controller<UITableViewDataSource, UISearchBarDelegate>

searchbar:textDidChange:

FiltersearchBar:textDidChange:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isEmpty {

content = atomicElements } else { content = atomicElements.filter{$0.name.hasPrefix(searchText)} } tableView?.reload() }

FiltersearchBar:textDidChange:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isEmpty {

content = atomicElements } else { content = atomicElements.filter{$0.name.hasPrefix(searchText)} } tableView?.reload() }

FiltersearchBar:textDidChange:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isEmpty == true {

content = atomicElements } else { content = atomicElements.filter{$0.name.hasPrefix(searchText)} } tableView?.reload() }

Original Array:

Filtered Array:

Closure:

FiltersearchBar:textDidChange:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isEmpty == true {

content = atomicElements } else { content = atomicElements.filter{$0.name.hasPrefix(searchText)} } tableView?.reload() }

Original Array:

Filtered Array:

Closure:

DemoFiltering

Only the worthy may pass.

Sums of Atomic Weights

Introducing Map & Reduce, in harmony like Ebony & Ivory.

Sum of Atomic Weights

Sum of Atomic WeightsTwo or more rows selected

Intermediate ObjectiveArray of selected atomic elements

F9

Eu63

Es99

Dy66

Cu29

Db105

Er68

content

Intermediate ObjectiveArray of selected atomic elements

F9

Eu63

Es99

Dy66

Cu29

Db105

Er68

content

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

Intermediate ObjectiveArray of selected atomic elements

2526272829303132

222324

indexPath.row

F9

Eu63

Es99

Dy66

Cu29

Db105

Er68

content

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

Intermediate ObjectiveArray of selected atomic elements

25 27 29 30

indexPathsForSelectedRows

31

F9

Eu63

Es99

Dy66

Cu29

Db105

Er68

content

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

Traditional ApproachFor in

var selectedElements = [AtomicElement]() if let indexPaths = tv?.indexPathsForSelectedRows { for ip in indexPaths { let currentElement = content[ip.row] selectedElements.append(currentElement) } }

Swiftier WayMap

let selectedElements = tv?.indexPathsForSelectedRows?.map{content[$0.row]}

var selectedElements = [AtomicElement]() if let indexPaths = tv?.indexPathsForSelectedRows { for ip in indexPaths { let currentElement = content[ip.row] selectedElements.append(currentElement) } }

Adding Values of ItemsTraditional way

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

.atomicWeight

Adding Values of ItemsTraditional way

Using a for-in loop

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

.atomicWeight

var d = 0.0 for element in selectedAtomicElements { d = d + element.atomicWeight }

Sum of Atomic Element WeightsSwift’s reduce() method

reduce(0.0, combine: {$0 + $1.atomicWeight})With Reduce()

var d = 0.0 for element in selectedAtomicElements { d = d + element.atomicWeight }

Using a for-in loop

F9

Eu63

Es99

Dy66

Cu29

selectedAtomicElements

.atomicWeight

Final Code SnippetAll together, now

tableView?.indexPathsForSelectedRows?.map{self.content[$0.row]}.reduce(0.0, combine: {$0 + $1.atomicWeight})

DemoMap & Reduce

Obtaining closure through closures.

Summary

You have existing Objective-C code? Keep it.You’re adding new code? Consider writing it in Swift.

More Information

Stefan LesserSwift Evangelistslesser@apple.com

Swift Language Documentationhttp://developer.apple.com/swift

Apple Developer Forumsdeveloper.apple.com/forums

Related Sessions

What’s new in Swift Presidio Tuesday 11:10AM

Swift and Objective-C Interoperability Mission Tuesday 1:30PM

Protocol Oriented Programming in Swift Marina Wednesday 2:30PM

Optimizing Performance in Swift Presidio Thursday 9:00AM

Swift in Practice Presidio Thursday 2:30PM

Building Better UIKit Apps with Swift Mission Wednesday 2:00PM