KEMBAR78
From android/java to swift (3) | PDF
From Android/Java to Swift (3)
Allan Shih
Agenda
● Subscripts
● Optional Chaining
● Error Handling
● Type Casting
● Nested Types
● Extensions
● Protocols
● Generics
● Reference
Subscripts
Subscripts enable you to query instances of a type by writing one or
more values in square brackets after the instance name.
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
Example of a read-only subscript
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is (threeTimesTable[6])")
// Prints "six times three is 18"
Optional Chaining
Optional chaining is a process for querying and calling properties,
methods, and subscripts on an optional that might currently be nil.
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
Optional Chaining
To use optional chaining, use a question mark in place of the
exclamation mark:
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has (roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// Prints "Unable to retrieve the number of rooms."
Error Handling
● Error handling is the process of responding to and recovering
from error conditions in your program.
● We need to choose one of these 4 approaches:
○ Propagate the error further up the call stack by declaring calling
function as throws
○ Handle the error with a do/catch block
○ Handle the error as an optional value, try?
○ Assert that the error will not occur, try!
Representing and Throwing Errors
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
Propagating Errors Using Throwing Functions
func canThrowErrors() throws -> String
func cannotThrowErrors() -> String
Propagating Errors Using Throwing Functions
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price -
coinsDeposited)
}
coinsDeposited -= item.price
Continue to propagate Errors
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
Handling Errors Using Do-Catch
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}
do/catch in swift
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional (coinsNeeded) coins.")
}
// Prints "Insufficient funds. Please insert an additional 2 coins."
Converting Errors to Optional Values
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
Disabling Error Propagation
Sometimes you know a throwing function or method won’t throw an
error at runtime.
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
Specifying Cleanup Actions
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}
Type casting
● Type casting is a way to check the type of an instance, or to treat
that instance as a different superclass or subclass from
somewhere else in its own class hierarchy.
● Type casting in Swift is implemented with the is and as operators.
Checking Type
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}
print("Media library contains (movieCount) movies and (songCount) songs")
// Prints "Media library contains 2 movies and 3 songs"
Downcasting
for item in library {
if let movie = item as? Movie {
print("Movie: (movie.name), dir. (movie.director)")
} else if let song = item as? Song {
print("Song: (song.name), by (song.artist)")
}
}
// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
Type Casting for Any and AnyObject
Swift provides two special types for working with nonspecific types:
● Any can represent an instance of any type at all, including function types.
● AnyObject can represent an instance of any class type.
Any example
var things = [Any]()
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, (name)" })
Any example
for thing in things {
switch thing {
case let someInt as Int:
print("an integer value of (someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive double value of (someDouble)")
case is Double:
print("some other double value that I don't want to print")
case let someString as String:
print("a string value of "(someString)"")
case let (x, y) as (Double, Double):
print("an (x, y) point at (x), (y)")
Nested Types
Swift enables you to define nested types, whereby you nest supporting
● enumeration
● class
● structure
within the definition of the type they support.
Nested Types in Action
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// BlackjackCard properties and methods
let suit: Suit
var description: String {
var output = "suit is (suit.rawValue),"
return output
}
}
Referring to Nested Types
To use a nested type outside of its definition context, prefix its name
with the name of the type it is nested within:
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "♡"
Extensions
Extensions in Swift can:
● Add computed instance properties and computed type properties
● Define instance methods and type methods
● Provide new initializers
● Define subscripts
● Define and use new nested types
● Make an existing type conform to a protocol
Cannot:
● Override existing functionality
● Add stored properties
● Add property observers to existing properties
Extension Syntax
extension SomeType {
// new functionality to add to SomeType goes here
}
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
Computed Properties
extension Double {
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is (oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is (threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"
Initializers
struct Rect {
var origin = Point()
var size = Size()
}
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
Methods
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
2.repetitions {
print("Hello!")
}
// Hello!
// Hello!
Protocols
A protocol defines a blueprint of methods, properties, and other
requirements that suit a particular task or piece of functionality.
protocol SomeProtocol {
// protocol definition goes here
}
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
Property Requirements
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
Method Requirements
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
func random() -> Double {
return lastRandom.truncatingRemainder(dividingBy:139968.0))
}
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: (generator.random())")
// Prints "Here's a random number: 0.37464991998171"
Initializer Requirements
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
Protocols as Types
● As a parameter type or return type in a function, method, or initializer
● As the type of a constant, variable, or property
● As the type of items in an array, dictionary, or other container
class Dice {
let generator: RandomNumberGenerator
init(generator: RandomNumberGenerator) {
self.generator = generator
}
func roll() -> Int {
return Int(generator.random()) + 1
}
}
Non-Generics
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
Generics
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
Non-Generics Stack
struct IntStack {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
Generic Stack
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
Push elements
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings
Protocols
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
Reference
● The Swift Programming Language (Swift 3.0.1)
● 从Java/Android到Swift iOS开发

From android/java to swift (3)

  • 1.
    From Android/Java toSwift (3) Allan Shih
  • 2.
    Agenda ● Subscripts ● OptionalChaining ● Error Handling ● Type Casting ● Nested Types ● Extensions ● Protocols ● Generics ● Reference
  • 3.
    Subscripts Subscripts enable youto query instances of a type by writing one or more values in square brackets after the instance name. subscript(index: Int) -> Int { get { // return an appropriate subscript value here } set(newValue) { // perform a suitable setting action here } }
  • 4.
    Example of aread-only subscript struct TimesTable { let multiplier: Int subscript(index: Int) -> Int { return multiplier * index } } let threeTimesTable = TimesTable(multiplier: 3) print("six times three is (threeTimesTable[6])") // Prints "six times three is 18"
  • 5.
    Optional Chaining Optional chainingis a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() let roomCount = john.residence!.numberOfRooms // this triggers a runtime error
  • 6.
    Optional Chaining To useoptional chaining, use a question mark in place of the exclamation mark: if let roomCount = john.residence?.numberOfRooms { print("John's residence has (roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // Prints "Unable to retrieve the number of rooms."
  • 7.
    Error Handling ● Errorhandling is the process of responding to and recovering from error conditions in your program. ● We need to choose one of these 4 approaches: ○ Propagate the error further up the call stack by declaring calling function as throws ○ Handle the error with a do/catch block ○ Handle the error as an optional value, try? ○ Assert that the error will not occur, try!
  • 8.
    Representing and ThrowingErrors enum VendingMachineError: Error { case invalidSelection case insufficientFunds(coinsNeeded: Int) case outOfStock } throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
  • 9.
    Propagating Errors UsingThrowing Functions func canThrowErrors() throws -> String func cannotThrowErrors() -> String
  • 10.
    Propagating Errors UsingThrowing Functions func vend(itemNamed name: String) throws { guard let item = inventory[name] else { throw VendingMachineError.invalidSelection } guard item.count > 0 else { throw VendingMachineError.outOfStock } guard item.price <= coinsDeposited else { throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited) } coinsDeposited -= item.price
  • 11.
    Continue to propagateErrors let favoriteSnacks = [ "Alice": "Chips", "Bob": "Licorice", "Eve": "Pretzels", ] func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws { let snackName = favoriteSnacks[person] ?? "Candy Bar" try vendingMachine.vend(itemNamed: snackName) }
  • 12.
    Handling Errors UsingDo-Catch do { try expression statements } catch pattern 1 { statements } catch pattern 2 where condition { statements }
  • 13.
    do/catch in swift varvendingMachine = VendingMachine() vendingMachine.coinsDeposited = 8 do { try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine) } catch VendingMachineError.invalidSelection { print("Invalid Selection.") } catch VendingMachineError.outOfStock { print("Out of Stock.") } catch VendingMachineError.insufficientFunds(let coinsNeeded) { print("Insufficient funds. Please insert an additional (coinsNeeded) coins.") } // Prints "Insufficient funds. Please insert an additional 2 coins."
  • 14.
    Converting Errors toOptional Values func someThrowingFunction() throws -> Int { // ... } let x = try? someThrowingFunction() let y: Int? do { y = try someThrowingFunction() } catch { y = nil }
  • 15.
    Disabling Error Propagation Sometimesyou know a throwing function or method won’t throw an error at runtime. let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
  • 16.
    Specifying Cleanup Actions funcprocessFile(filename: String) throws { if exists(filename) { let file = open(filename) defer { close(file) } while let line = try file.readline() { // Work with the file. } // close(file) is called here, at the end of the scope. } }
  • 17.
    Type casting ● Typecasting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy. ● Type casting in Swift is implemented with the is and as operators.
  • 18.
    Checking Type var movieCount= 0 var songCount = 0 for item in library { if item is Movie { movieCount += 1 } else if item is Song { songCount += 1 } } print("Media library contains (movieCount) movies and (songCount) songs") // Prints "Media library contains 2 movies and 3 songs"
  • 19.
    Downcasting for item inlibrary { if let movie = item as? Movie { print("Movie: (movie.name), dir. (movie.director)") } else if let song = item as? Song { print("Song: (song.name), by (song.artist)") } } // Movie: Casablanca, dir. Michael Curtiz // Song: Blue Suede Shoes, by Elvis Presley
  • 20.
    Type Casting forAny and AnyObject Swift provides two special types for working with nonspecific types: ● Any can represent an instance of any type at all, including function types. ● AnyObject can represent an instance of any class type.
  • 21.
    Any example var things= [Any]() things.append(0) things.append(0.0) things.append(42) things.append(3.14159) things.append("hello") things.append((3.0, 5.0)) things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")) things.append({ (name: String) -> String in "Hello, (name)" })
  • 22.
    Any example for thingin things { switch thing { case let someInt as Int: print("an integer value of (someInt)") case let someDouble as Double where someDouble > 0: print("a positive double value of (someDouble)") case is Double: print("some other double value that I don't want to print") case let someString as String: print("a string value of "(someString)"") case let (x, y) as (Double, Double): print("an (x, y) point at (x), (y)")
  • 23.
    Nested Types Swift enablesyou to define nested types, whereby you nest supporting ● enumeration ● class ● structure within the definition of the type they support.
  • 24.
    Nested Types inAction struct BlackjackCard { // nested Suit enumeration enum Suit: Character { case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣" } // BlackjackCard properties and methods let suit: Suit var description: String { var output = "suit is (suit.rawValue)," return output } }
  • 25.
    Referring to NestedTypes To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within: let heartsSymbol = BlackjackCard.Suit.hearts.rawValue // heartsSymbol is "♡"
  • 26.
    Extensions Extensions in Swiftcan: ● Add computed instance properties and computed type properties ● Define instance methods and type methods ● Provide new initializers ● Define subscripts ● Define and use new nested types ● Make an existing type conform to a protocol Cannot: ● Override existing functionality ● Add stored properties ● Add property observers to existing properties
  • 27.
    Extension Syntax extension SomeType{ // new functionality to add to SomeType goes here } extension SomeType: SomeProtocol, AnotherProtocol { // implementation of protocol requirements goes here }
  • 28.
    Computed Properties extension Double{ var m: Double { return self } var cm: Double { return self / 100.0 } var mm: Double { return self / 1_000.0 } var ft: Double { return self / 3.28084 } } let oneInch = 25.4.mm print("One inch is (oneInch) meters") // Prints "One inch is 0.0254 meters" let threeFeet = 3.ft print("Three feet is (threeFeet) meters") // Prints "Three feet is 0.914399970739201 meters"
  • 29.
    Initializers struct Rect { varorigin = Point() var size = Size() } extension Rect { init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }
  • 30.
    Methods extension Int { funcrepetitions(task: () -> Void) { for _ in 0..<self { task() } } } 2.repetitions { print("Hello!") } // Hello! // Hello!
  • 31.
    Protocols A protocol definesa blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. protocol SomeProtocol { // protocol definition goes here } struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here }
  • 32.
    Property Requirements protocol FullyNamed{ var fullName: String { get } } struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed") // john.fullName is "John Appleseed"
  • 33.
    Method Requirements protocol RandomNumberGenerator{ func random() -> Double } class LinearCongruentialGenerator: RandomNumberGenerator { var lastRandom = 42.0 func random() -> Double { return lastRandom.truncatingRemainder(dividingBy:139968.0)) } } let generator = LinearCongruentialGenerator() print("Here's a random number: (generator.random())") // Prints "Here's a random number: 0.37464991998171"
  • 34.
    Initializer Requirements protocol SomeProtocol{ init(someParameter: Int) } class SomeClass: SomeProtocol { required init(someParameter: Int) { // initializer implementation goes here } }
  • 35.
    Protocols as Types ●As a parameter type or return type in a function, method, or initializer ● As the type of a constant, variable, or property ● As the type of items in an array, dictionary, or other container class Dice { let generator: RandomNumberGenerator init(generator: RandomNumberGenerator) { self.generator = generator } func roll() -> Int { return Int(generator.random()) + 1 } }
  • 36.
    Non-Generics func swapTwoInts(_ a:inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } func swapTwoStrings(_ a: inout String, _ b: inout String) { let temporaryA = a a = b b = temporaryA }
  • 37.
    Generics func swapTwoValues<T>(_ a:inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA } var someInt = 3 var anotherInt = 107 swapTwoValues(&someInt, &anotherInt) // someInt is now 107, and anotherInt is now 3
  • 38.
    Non-Generics Stack struct IntStack{ var items = [Int]() mutating func push(_ item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } }
  • 39.
    Generic Stack struct Stack<Element>{ var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } }
  • 40.
    Push elements var stackOfStrings= Stack<String>() stackOfStrings.push("uno") stackOfStrings.push("dos") stackOfStrings.push("tres") stackOfStrings.push("cuatro") // the stack now contains 4 strings
  • 41.
    Protocols let fromTheTop =stackOfStrings.pop() // fromTheTop is equal to "cuatro", and the stack now contains 3 strings
  • 42.
    Reference ● The SwiftProgramming Language (Swift 3.0.1) ● 从Java/Android到Swift iOS开发