ルーム情報 : "droom" (289件)
最近更新されたメモ一覧 :
docs
被リンクメモ一覧 : (1件)
[index]
[Home] [List] [Recent] [Orphan] [Help] [Edit] [Remove]

Swift : summary

Basics

Constants and Variables

定数と変数の名前にはUnicode文字を含むほぼ任意の文字を使用できる。

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
var x =0.0, y = 0.0, z = 0.0
var welcomeMEssage: String
var red, green, blue: Double

Optionals

let possbleNumber = "123"
let convertedNumber = Int(possbleNumber)
// convertedNumberはInt?またはoptional Int.

var serverResponseCode: Int? = 404 // actual value.
serverResponseCode = nil // now contains no value.

var surveyAnswer: String?

// Forced Unwrapping
if convertedNumber != nil { ... }

// Optional Binding (if let constantName = someOptional {} )
if let actualNumber = Int(possibleNumber) {...}

for-in

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names { print("Hello, \(name)!") }
let numberOfLegs = ["spider":8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs { print("\(animalName)s have \(legCount) legs") }
for index in 1...5 { print("\(index) times 5 is \(index * 5)") }
let base = 3
let power = 10
var answer = 1
for _ in 1...power { answer *= base }
let minutes = 60
for tickMark in 0..<minutes { // 60 times. }
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) { //  0, 5, 10...50, 55 }

While Loops, Repeat-While

while condition { statement }
repeat { statement } while condition

If

if condition { statement } else if condition { statement } else { statement }

Switch

breakしなくてもcaseの最後に次のcaseにfallthroughされない。
途中で抜けるためにbreak使用可。

switch 'some value to consider' {
case value1:
  respond to value 1
case value2, value3:
  respond to value 2 or 3
default:
  otherwise, do something else
}

Interval Matching

case 0:
  ...
case 1..<5:
  ...
case 5..<12:
  ...
default:
  ...

Tuples

case (0, 0):
  ...
case (_, 0):
  ...
case (-2...2, -2...2):
  ...
default:
  ...

Value Bindings

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
  print ("on the x-axis with an x value of \(x)")
case (0, let y):
  print("on the y-axis with a y value of \(y)")
case let (x, y):
  print("somewhere else at (\(x), \(y))")
}

Where

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
  print("(\(x), \(y)) is on the line x == y")
...

Control Transfer Statement

gameLoop: while square != finalSquare {
  ...
  switch square + diceRoll {
  ...
  case finalSquare:
    break gameLoop
  case let newSquare where newSquare > finalSquare:
    continue gameLoop
  ...
}

Early Exit

guard文は条件がtrueであればそのまま処理を続け、trueでなければelse節のコードが実行される。else節は必ず存在しなければならない。

guard let name = person["name"??] else { return }

Checking API Availability

ビルトインでサポートされるAPI可用性のチェック。ifまたはguard文で使用。

if #available(iOS 9, OSX 10.10, *) { ... } else { それ以前 }

if #available(platform name version, ..., *) {
    statements to execute if the APIs are available
} else {
    fallback statements to execute if the APIs are unavailable
}

platform nameにはiOS, OSX, watchOSを使用する。iOS 8、あるいはiOS 8.3といった形でも指定できる。

関数

//greet(person:)

func greet(person: String) -> String {
  let greeting = "Hello, " + person + "!"
  return greeting
}

複数のパラメータ

func greet(person: String, alreadyGreeted: Bool) -> String { ... }
without return values
func greet(person: String) { ... } // 実際にはVoidが返される。Voidとは空のタプル ()

multiple return values

func minMax(array: [Int]) -> (min: Int, max: Int) { ... }

Optional Tuples Return Types

func minMax(array: [Int]) -> (min: Int, max: Int)? { ... } // (min: Int?, max: Int?) とは異る

Function Argument Labels and Parameter Names

func someFunction(firstParameterName: Int, secondParameterName: Int){ ... }
-> someFunction(firstParameterName: 1, secondParameterName: 2)

func someFunction(argumentLabel parameterName: Int) { ... }
func greet(person: String, from hometown: String) -> String { ... }
-> greet(perton: "Bill", from: "Cupertino")

omitting argument labels

func someFunction(_ firstParameterName: Int, secondParameterName: Int) { ... }

default parameter values

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) { ... }
-> someFuntion(parameterWithoutDefault: 4)

variadic parameters 可変長パラメータ

func arithmeticMean(_ numbers: Double...) -> Double { ... for number in numbers { ... } ... }

In-Out Parameters

func swapTwoInts(_ a: inout Int, _ b: inout Int) { ... }
-> swapTwoInts(&someInt, &anotherInt)

Function Types

func addTwoInts(_ a: Int, _ b: Int) -> Int { ... }
=> (Int, Int) -> Int

var mathFunction: (Int, Int) -> Int  = addTwoInts
mathFunction(2, 3)

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int){ ... }

クロージャ Closures

{ ('parameters') -> 'return type' in
  'statements'
}

func backward(_ s1: String, _ s2: String) -> Bool { return s1 > s2 }
reversedNames = names.sorted(by: backward)
reversedNames  = names.sorted(by: { (s1: String, s2: String) -> Bool in 
  return s1 > s2
})
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 })
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 })
reversedNames = names.sorted(by: { $0 > $1 })
reversedNames = names.sorted(by: >)

Trailing Closures - 後置クロージャ

func someFunctionThatTakesAClosure(closure: () -> Void){ ... }

someFunctionThatTakesAClosure(closure: { ... })
someFunctionThatTakesAClosure(){ ... }

reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 } // クロージャ式・関数が唯一の引数で後置する場合には()不要

複数のクロージャを引数とする関数は、最初の引数のラベルを省略し、残りの引数にラベルする。

func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void){ ... }

loadPicture(from: someServer) { picture in
  someView.currentPicture = picture
} onFailure: {
  ...
}

値のキャプチャ

func makeIncrementer(forIncrement amout: Int) -> () -> Int {
  var runningTotal = 0
  func incrementer() -> Int {
    runningTotal += amout
    return runningTotal
  }
  return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)

incrementByTen() // returns a value of 10
incrementByTen() // returns a value of 20
incrementByTen() // returns a value of 30

let incrementBySeven = makeIncrementer(forINcrement: 7)
incrementBySeven() // returns a value of 7
incrementByTen() // returns a value of 40

クロージャは参照型である。

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen() // returns a value of 50
incrementByTen() // returns a value of 60

クロージャをエスケープする。(@noescapeはobsolete? @escapingを使用する)
@escapingをマークせずにエスケープするとコンパイルエラー。

var completionHandlers: [() ->Void]()
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
  completionHandlers.append(completionHandler) // 関数の外側で宣言された配列に追加。
}

この辺りはよく分からない。再度勉強すること。https://docs.swift.org/swift-book/LanguageGuide/Closures.html

自動クロージャ Autoclosures

列挙型 Enumerations

enum SomeEnumeration { ... }

enum CompassPoint {
  case north
  case south
  case east
  case west
}

enum Planet {
  case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

var directionToHead = CompassPoint.west
directionToHead = .east // 一度型が決まれば略記可能。

switch構文における列挙型の一致

directionToHead = .south
switch directionToHead {
case .north: ...
case .south: ...
...
} // 全てのcaseを扱わないならdefault節が必須。

Iteration over Enumeration Cases

enum Beverage: CaseIterable {
  vase coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count

for beverage in Beverage.allCases { ... }

列挙型 関連値

enum Barcode {
  case UPCA(Int, Int, Int, Int)
  case QRFode(String)
}

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
  print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(...
}

// 全ての関連値を定数・変数として取り出す場合にはcase前にアノテーションとしてletを置く。
case let .UPCA(numberSystem, manufacturer, product, check):
    print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")

Raw値 Raw Value

// 全てユニークな値にする必要がある。
enum ASCIIControlCharacter: Character {
  case Tab = "\t"
  case LineFeed = "\n"
  case CarriageReturn = "\r"
}

暗黙のうちに割り当てられるraw値

enum Planet: Int {  case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
// 順に1、2、3…が割り当てられる。
enum CompassPoint: String { case North, South, East, West }
// それぞれ"North"などの文字列が割り当てられる。

let earthsOrder = Planet.Earth.rawValue // raw値を取り出す。

let possiblePlanet = Planet(rawValue: 7) // possiblePlanetはPlanet?型。raw値による初期化。
public protocol CaseIterable {

    /// A type that can represent a collection of all values of this type.
    associatedtype AllCases : Collection where Self.AllCases.Element == Self

    /// A collection of all values of this type.
    public static var allCases: Self.AllCases { get }
}
enum Direction2: CaseIterable {
    case east
    case west
    case north
    case south
}

// [__lldb_expr_8.Direction1.east, __lldb_expr_8.Direction1.west, __lldb_expr_8.Direction1.north, __lldb_expr_8.Direction1.south]
print(Direction2.allCases)

列挙型そのものを渡すことができる。

struct Sample {
  var characters: String

  enum CodingKeys: String, CodingKey {
    case characters 
  }
}

extension Sample: Decodable {
  init(from decoder: Decoder) throw {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    ...
}

列挙型の定義そのものを渡すことができる様子。例では"- Swift.String #0" が渡される。

構造体とクラス Structures and Classes

class SomeClass { ... }
struct SomeStructure { ... } // クラス・構造体の名前は大文字から。プロパティ・メソッドは小文字から始まる文字列とする。
struct Resolution {
  var width = 0
  var height = 0
}
class VideoMode {
  var resolutin = Resolution()
  var interlaced = false
  var frameRate = 0.0
  var name: String?   // nilが代入される
}

インスタンス生成

let someResolution = Resolution()
let someVideoMode = VideoMode()

プロパティへのアクセス

someResolution.width
someVideoMode.resolution.width
someVideoMode.resolution.width = 1280

構造体のメンバーワイズイニシャライザ。クラスにはない。

let vga = Resolution(width: 640, height: 480) // 自動生成されるイニシャライザ。

プロパティ properties

struct FixedLenghRange {
  var firstValue: Int
  let length: Int
}
var rangeOfThreeItems = FixedLenghRange(firstValue: 0, length: 3)

class DataManager {
  lazy var importer = DataImoprter()
  var data = [String]()
}

構造体のインスタンスを生成して定数に代入すると、インスタンスのプロパティは変数であっても変更することができない。

コンピューテッドプロパティ

struct Point { var x = 0.0, y = 0.0 }
struct Size { var width = 0.0, heigth = 0.0 }
struct Rect {
  var origin = Point()
  var size = Size()
  var center: Point {
    get {
      let centerX = origin.x + (size.width / 2)
      let centerY = origin.y + (size.height / 2)
      return Point(x: centerX, y: centerY)
    }
    set(newCenter) {
      origin.x = newCenter.x - (size.width / 2)
      origin.y = newCenter.y - (size.height / 2)
    }
  }
}

// 簡易setter宣言 - 新しい値の名前を定義していない場合、デフォルトの名前newValueが使用される。
set {
  origin.x = newValue.x - (size.width / 2)
  origin.y = newValue.y - (size.height / 2)
}

setterがなくgetterのみのコンピューテッドプロパティは読取専用。
読取専用の場合、getキーワードと{}を省略できる。

struct Cuboid {
  var width = 0.0, height = 0.0, depth = 0.0
  var volume: Double {
    return width * height * depth
  }
}

プロパティオブザーバ

class StepCounter {
  var totalSteps: Int = 0 {
    willSet(newTotalSteps){ // 値が保管される直前に呼び出される。
      ... // newTotalStepsを定義しなければnewValueが利用できる。
    }
    didSet { // 値が保管された直後に呼び出される。
      ... // oldValueを利用する。別のパラメータ名を付けることはできない。
    }
  }
}

Property Wrappers

 @propertyWrapper
struct TwelveOrLess {
  private var number: Int
  init() { self.number = 0 }
  var wrappedValue: Int {
    get { return number }
    set { number = min(newValue, 12) }
  }
}

struct SmallRectangle {
  @TwelveOrLess var height: Int
  @TwelveOrLess var width: Int
}

つまり、wrappedValueの扱いを定義したwrapperを作成し、それをプロパティに設定できる?
このあたりは新しいらしく日本語訳なし。初期値の定義についてかなり詳しく解説されている。

タイププロパティシンタックス

struct SOmeStructure {
  static var storedTypeProperty = "Some value."
  static var computedTypeProperty: Int {
      return 1
  }
}
enum SomeEnumeration {
  static var storedTypeProperty = "Some value."
  static var computedTypeProperty: Int {
      return 6
  }
}
class SomeClass {
  static var storedTypeProperty = "Some value."
  static var computedTypeProperty: Int {
      return 27
  }
  class var overrideableComputedTypeProperty: Int {
      return 107
  }
}

SomeStructure.storedTypeProperty

メソッド Methods

class Counter {
  var count = 0
  func increment() {
      count += 1
  }
  func increment(by amount: Int) {
      count += amount
  }
  func reset() {
      count = 0
  }
}
struct Point {
  var x = 0.0, y = 0.0
  mutating func moveBy(deltaX: Double, y deltaY: Double) {
      x += deltaX
      y += deltaY
  }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0) // -> (3.0, 4.0)

こうも書ける。

struct Point {
  var x = 0.0, y = 0.0
  mutating func moveBy(deltaX: Double, deltaY: Double){
      self = Point(x: x + deltaX, y: y + deltaY)
  }
}
enum TriStateSwitch {
  case Off, Low, High
  mutating func next() {
    switch self {
    case Off:
      self = Low
    case Low:
      self = High
    case High:
      self = Off
    }    
  }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next() // -> ovenLightは.Highとなる。

タイプメソッド Type Methods

class SomeClass {
  class func someTypeMethod() {
      // some.
  }
}
SomeClass.someTypeMethod()
struct LevelTracker {
  static var highestUnlockedLevel = 1
  static func unlockLevel(level: Int) {
      if level > highestUmnlockedLevel { highestUnlockedLevel = level }
  }
  static func levelIsUnlocked(level: Int) -> Bool {
      return level <= highestUnlockedLevel
  }
  
  var currentLevel = 1
  mutating func advanceToLevel(level: Int) -> Bool {
      if LevelTracker.levelIsUnlocked(level){
          currentLevel = level
          return true
      } else {
          return false
      }
  }
}

サブスクリプト Subscript

subscript(index: Int) -> Int {
  get { ... }
  set(newValue){ ... } // 定義しなければ'newValue'がパラメータとなる。
}

subscript(index: Int) -> Int {
  // setがない場合にはgetキーワードを省略できる。
}

struct TimesTable {
  let multiplier: Int
  subscript(index: Int) -> Int {
    return multiplier * index    
  }
}
let threeTimesTable = TimesTable(multiplier: 3)
threeTimesTable[6] // -> 18
subscript(row: Int, column: Int) -> Double {...}

継承 Inheritance

class Vehicle {
  var currentSpeed = 0.0
  var description: String {
      return "traveling at \(currentSpeed) miles per hour"
  }
  func makeNoise(){
    // do nothing.    
  }
}

class SomeSubclass: SomeSuperClass {
  // サブクラス定義
}

class Bicycle: Vehicle {
  var hasBasket = false
}
class Train: Vehicle {
  override func makeNoise() {
      //...
  }
}
class Car: Vehicle {
  var gear = 1
  override var description: String {
      return super.description + " in gear \(gear)"
  }
}
class AutomaticCar: Car {
  override var currentSpeed: Double {
    didSet {
        gear = Int(currentSpeed / 10.0) + 1
   }    
  }
}

イニシャリゼーション Initialization

init (){
  // ...
}

struct Fahrenheit {
  var temperature: Double
  init(){
    temperature = 32.0    
  }
}

struct Fahrenheit {
  var temperature = 32.0
}

struct Celsius {
  var temperatureInCelsius: Double
  init(fromFahrenheit fahrenheit: Double){
    temperatureInCelsius = (fahrenheit - 32.0) / 1.8    
  }
  init(fromKelvin kelvin: Double){
    temperatureInCelsius = kelvin - 273.15    
  }
  init(_ celsius: Double){{
    temperatureInCelsius = celsius    
  }
}
class SurveyQuestion {
  var text: String
  var response: String?  // オプショナル型プロパティ
  init(text: String){ self.text = text }
  func ask(){ print(text) }
}

デフォルトイニシャライザ

struct Size {
  var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

クラスの継承と初期化

failableイニシャライザ

struct Animal {
  let species: String
  init?(species: String){
    if species.isEmpty { return nil }
    self.species = species    
  }
}
enum TemperatureUnit {
  case Kelvin, Celsius, Fahrenheit
  init?(symbol: Character){
      switch symbol {
      case "K":
          self = .Kelvin
      case "C":
          self = .Celsius
      case "F":
          sefl = .Fahrenheit
      default:
          return nil
      }
  }
}
class SomeClass {
  let someProperty: SomeType = {
      //...
      return someValue
  }()
}

requiredイニシャライザ

class SomeClass {
  required init() {
    // something.    
  }
}

プロパティのデフォルト値をクロージャまたは関数で設定

class SomeClass {
  let someProperty: SomeType = {
      // something...
      return someValue  // SomeTypeと同じ型の戻り値を返す。
  }() // クロージャの後に()が必要。
}

デイニシャリゼーション

deinit {
  // something.
}

自動参照カウント

オプショナルチェーン

class Person { var residence: Residence? }
class Residence { var numberOfRooms = 1 }

let john = Person()
let roomCount = johjn.residence!.numberOfRooms // 実行時エラー

if let roomCount = john.residence?.numberOfRooms {
  // roomCountが存在する場合
} else {
  // 存在しない場合
}

この例では、residenceがnilの場合を考えてnumberOfRoomsはInt?型の値を返す。

if let firstRoomName = john.residence?[0].name { ... }

エラー処理

enum VendingMachineError: Error {
  case InvalidSelection
  case InsufficientFunds(coinsNeeded: Int)
  case outOfStock
}
throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)
func conThrowErrors() throws -> String
func cannotThrowErrors() -> String
struct PurchasedSnack {
  let name: String
  init(name: String, vendingMachine: VendingMachine) throws {
    try vendingMachine.vend(itemNamed: name)
    self.name = name
  }
}
do {
  try 'expression'
    'statements'
} catch 'pattern1' {
  'statements'
} catch 'pattern2' where 'condition' {
  'statements'
}

エラーのクリーンアップ

func processFile(filename: String) throws {
  if exists(filename) {
      let file = open(filename)
      defer {
        close(file)
      }
      while let line = try file.readline() {
        // ファイルを扱う。    
      }
      // この場所でdeferのclose(file)が呼び出される。
  }
}

型キャスト

class MediaItem {
  var name: String
  init(name: String) {
      self.name = name
  }
}

class Movie: MediaItem {
  var director: String
  init(name: String, director: String) {
      self.director = director
      super.init(name: name)
  }
}

class Song: MediaItem {
  var artist: String
  init(name: String, artist: String) {
      self.artist = artist
      super.init(name: name)
  }
}

///
for item in library {
  if item is Movie {
      movieCount += 1
  } else if item is Song {
      songCount += 1
  }
}

//
for item in library {
  if let movie = item as? Movie { ... }
  else if let song = item as? Song { ...}
}

for object in someObjects {
  let movie = object as! Movie
  //...
}

for movie in someObjets as! [Movie] { ... }

ネストされた型

let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue

エクステンション

extension SomeType { ... }
extension SomeType: SOmeProtocol, AnotherProtocol { ... }
extension Rect {
  init(center: Point, size: Size){
    let originX = center.x - (size.width / 2)
    let originY = cneter.y - (size.height / 2)
    self.init(origin: Point(x: originX, y: originY), size: size)    
  }
}
extension Int {
  func repetitions(task: () -> Void) {
      for _ in 0..<self {
          task()
      }
  }
}

3.repetitions({
  print("hello!")
})

// 後置クロージャ
3.repetitions {
  print("hello!")
}
extension Int {
  mutating func square() {
    self = self * self    
  }
}

// 数値の右端からn番目の数値を返す。123456789[0]なら9
extention Int {
  subscript(digitIndex: Int) -> Int {
    var decimalBase = 1
    for _ in 0..<digitIndex {
      decimalBase *= 10    
   }    
   return (self / decimalBase) % 10
  }
}

extension Int {
  enum Kind {
      case Negative, Zero, Positive
  }
  var kind: Kind {
    switch self {
    case 0:
        return .Zero
    case let x where x > 0:
        return .Positive
    default:
        return .Negative    
    }    
  }
}

プロトコル

protocol SomeProtocol {
  // プロトコルの定義
}

struct SomeStructure: FirstProtocol, AnotherProtocol {
  // 構造体の定義
}

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
  // クラスの定義
} 
protocol SomeProtocol {
  var mustBeSettable: Int { get set }
  var doesNotNeedToBeSettable: Int { get }
}

protocol AnotherProtocol {
  static var someTypeProperty: Int { get set }
}
protocol FullyNamed {
  var fullName: String { get }
}

struct Person: FullyNamed {
  var fullName: String
}
let john = Person(fullName: "John Appleseed")
class Starship: FullyNamed {
  var prefix: String?
  var name: String
  init(name: String, prefix: String? = nil) {
    self.name = name
    self.prefix = prefix    
  }
  var fullName: String{
      return (prefix != nil ? prefix! + " " : "") + name
  } 
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
protocol SomeProtocol {
  static func someTypeMethod()
}

///

protocol RandomNumberGenerator {
  func random() -> Double
}

class LinearCongruentialGenerator: RandomNumberGenerator {
  var lastRandom = 42.0
  let m = 1339968.0
  let a = 3877.0
  let c = 29573.0
  func random() -> Double {
    lastRandom = ((lastRandom * a -+ c) % m)
    return lastRandom / m    
  }
}
let generator = LinearCongruentialGEnerator()
generator.random()
protocol Togglable {
  mutating func toggle()
}

enum OnOffSwitch: Togglable {
  case Off, On
  mutating func toggle() {
    switch self {
    case Off:
        self = On
    case On:
        self = Off    
    }    
  }
}
var lightSwitch = OnOffSwitch.Off
lightSwitch.toggle()
protocol SomeProtocol {
  init(somePrameter: Int)
}

class SomeClass: SomeProtocol {
  required init(someParameter: Int){
    // 実装    
  }
}

///

protocol SomeProtocol {
  init()
}

class SomeSuperClass {
  init () {
    // 実装    
  }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
   // SomeProtocolからのrequiredと、SomeSuperClassからのoverride
   required override init(){
         // 実装
   }
}
class Dice {
  let sides: Int
  let generator: RandomNumberGenerator
  init(sides: Int, generator: RandomNumberGenerator){
    self.sides = sides
    self.generator = generator
  }
  func roll() -> Int {
    return Int(generator.random() * Double(sides)) + 1    
  }
}
protocol DiceGame {
  var dice: Dice { get }
  func play()
}
protocol DiceGameDelegate: AnyObject { // <- クラス限定プロトコル v5.3
  func gameDidStart(_ game: DiceGame)
  func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
  func gameDidEnd(_ game: DiceGame)
}
protocol TextRepresentable {
  var textualDescription: String { get }
}

extension Dice: TextRepresentable {
  var textualDescription: String {
    return "A \(sides)-sided dice"    
  }
} 
let things: [TextRepresentable] = [game, d12, simonTheHamster]

for thing in things {
  print(thing.textualDescription)
}
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { ... }

protocol PrettyTextualRepresentable: TextRepresentable {
  var prettyTextualDescription: String { get }
}
protocol SomeClassOnlyProtocol: AnyObject, SomeInteritedProtocol { ... }
protocol Named { var name: String { get }}
protocol Aged {var age: Int { get }}
protocol Person: Named, Aged {
  var name: String
  var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged){ ... }
let birthdayPerson = Person(name: "Malcomlm", age: 21)
wishHappyBirthday(to: birthdayPerson)
protocol HasArea {
  var area: Double { get }
}
class Circle: HasArea { ... }
class Country: HasArea { ... }
class Animal { ... }

let objects: [AnyObject] = [
  Circle(radius: 2.0),
  Country(area: 243_610),
  Animal(legs: 4)
]

for object in objects {
  if let objectWithArea = object as? HasArea { ... } else { ... }
}
extension RandomNumberGenerator {
  func randomBool() -> Bool { return random() > 0.5 }
}
extension Collection where Element: TextRepresentable {
  func allEqual() -> Bool {
    for element in self {
      if element != self.first { return false }
    }    
    return true
  }
}

ジェネリクス

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
  let temporaryA = a
  a = b
  b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)

// Generic function
func swapTwoValues<T>(_ a: inout T, _ b: inout T) { ... }
swapTwoValues(&someInt, &anotherInt)
// Swift standard library has 'swap(_:_:)' function.

struct Stack<Element> {
  var items = [Element]()
  mutating func push(item: Element) {
    items.append(item)
  }
  mutating func pop() -> Element {
    return items.removeLast()
  }
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")

// Extension
extension Stack {
  var topItem: Element? {
    return items.isEmpty ? nil : items[items.count - 1]
  }
}
// Element型のオプショナル値を返す。

// 型制約シンタックス
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U){...}
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
  for (index, value) in array.enumerated() {
    if value == valueToFind {
      return index
    }
  }
  return nil
}

func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
  for (index, value) in array.enumerated() {
    if value == valueToFind {
      return index
    }
  }
  return nil
}
// Associated Types
protocol Container {
  associatedtype Item
  mutating func appen(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

struct Stack<Element>: Container {
  var items = [Element]()
  mutating func push(_ item: Element) {
    items.append(item)
  }
  mutating func pop() -> Element {
    return items.removeLast() 
    // これ、確実にElementが返るとは限らないね。
    // items.count == 0ならnilを返すことにして戻り値はElement!がよさそう。
  }
  
  mutating func append(_ item: Element) {
    self.push(item)
  }
  var count: Int {
    return items.count
  }
  subscript(i: Int) -> Element {
    return items[i]
  } 
}
extension Array: Container {}
//Associated typeに制限を付加する。
protocol Container {
  associatedtype Item: Equatable
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

// 関連型の制限をうけたプロトコルを使用する
protocol SuffixableContainer: Container {
  associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
  func suffix(_ size: Int) -> Suffix
}

この節については理解が進んでいない。また後日。邦訳版とはまったく内容が異なるため原文を読むこと。

アクセス制御

高度な演算子

// 二項演算子
struct Vector2D {
  var x = 0.0, y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
  return Vector2D(x: left.x + right.x, y: left.y + right.y)
}

// 単項演算子
// これは前置単項演算子のためprefixを付加する。
extension Vector2D {
  static prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
  }
}
let negative = -positive

// 複合代入演算子
extension Vector2D {
  static func += (left: inout Vector2D, right: Vector2D) {
    left = left + right
  }
}

// Equivalence Operators
extension Vector2D: Equatable {
  static func == (left: Vector2D, right: Vector2D) -> Bool {
    return (left.x == right.x) && (left.y == right.y)
  } 
} 
[Home] [List] [Recent] [Orphan] [Help] [Edit] [Remove]
-->