代々木で働く19歳エンジニアのブログ

思ったこととか、技術的なこと書きます。

Swift ざっくり文法 (4)

  • Class
import Foundation

class Myclass {
    let msg:String
    let name:String?
    
    init(msg:String = "hello") {
        self.msg = msg
        self.name = nil
    }
    
    init(msg:String = "hello", name:String) {
        self.msg = msg
        self.name = name
    }
    
    func hello() {
        var helloMsg:String
        if let user = name {
            helloMsg = user + "san" + msg
        } else {
            helloMsg = msg
        }
        print(helloMsg)
    }
}
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let myObj = Myclass()
        myObj.hello() // hello
        let myObjWithMsg = Myclass(msg: "good night")
        myObjWithMsg.hello() // good night
        let myObjWithName = Myclass(name: "Alex")
        myObjWithName.hello() // Alex、hello
        let myObjWithMsgAndName = Myclass(msg: "good night", name: "Alex")
        myObjWithMsgAndName.hello() // Alex、good night
    }
---
}
  • Convenience initializer
class Myclass {
    let msg:String
    let name:String?

-    init(msg:String = "hello") {
-        self.msg = msg
-        self.name = nil
-    }

-    init(msg:String = "hello", name:String) {
+    init(msg:String, name:String) {
        self.msg = msg
        self.name = name
    }
    
+    convenience init (msg:String = "hello") {
+        self.init(msg: msg, name: "Anonymous")
+    }    
}
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let myObj = Myclass()
-        myObj.hello() // hello
+        myObj.hello() // Anonymous, hello
        let myObjWithMsg = Myclass(msg: "good night")
-        myObjWithMsg.hello() // good night
+        myObjWithMsg.hello() // Anonymous,  good night
-        let myObjWithName = Myclass(name: "Alex")
-        myObjWithName.hello() // Alex、hello
        let myObjWithMsgAndName = Myclass(msg: "good night", name: "Alex")
        myObjWithMsgAndName.hello() // Alex、good night
    }
}

convenience initializerを使うと、複数のinitializerがあるときに、別のinitializerを呼ぶことができる。

  • stored property と、computed property
    • stored propertyは、定数・変数で定義される
    • computed propertyは、関数を介して値をやり取りする。値を保持しておらず、設定値を内部的に宣言しておいた定数や変数に設定して保管する
class Circle {
    var radius:Double = 1.0 // stored property
    var area:Double { // computed property
        get{ // property への参照
            return radius * radius * Double.pi
        }
        set(meseki){ // property への値の設定
            radius = sqrt(meseki / Double.pi)
        }
    }
}

let myCicle = Circle()
print("\(myCicle.radius)") // 1.0
print("\(myCicle.area)") // 3.14159265358979
myCicle.area *= 2
print("\(myCicle.radius)") // 1.4142135623731
print("\(myCicle.area)") // 6.28318530717959
myCicle.radius = 3.0
print("\(myCicle.radius)") // 3.0
print("\(myCicle.area)") // 28.2743338823081

read only の property

class Circle {
    var radius:Double = 1.0
    var area:Double {
        get{
            return radius * radius * Double.pi
        }
-        set(meseki){
-            radius = sqrt(meseki / Double.pi)
-        }
    }
}

let myCicle = Circle()
myCicle.radius = 3.0
print("\(myCicle.radius)") // 3.0
print("\(myCicle.area)") // 28.2743338823081

+ myCicle.area = 300 // error: cannot assign to property: 'area' is a get-only property

Read onlyであれば以下のようにも書ける

class Circle {
    var radius:Double = 1.0
    var area:Double {
-        get{
            return radius * radius * Double.pi
-        }
    }
}
  • property observer ( propertyに値がsetされたことをwillSet, didSetで知ることができる )
    • willSetは値が更新される直前に呼ばれ、新しくsetされる値に newValue でアクセスできる
    • didSetは値が更新された直後に呼ばれ、更新前の値に oldValue でアクセスできる
class Player {
    var times = 0
    var level:Int {
        willSet {
            print("------")
            print("willSet \(newValue)")
        }
        
        didSet {
            if oldValue != level {
                times += 1
                print("\(times) update\n\(oldValue) -> \(level)")
            } else {
                print("no changes")
            }
        }
    }
    
    init () {
        level = 0
    }
}

var thePlayer = Player()
thePlayer.level = 10
thePlayer.level = 10
thePlayer.level = 20

// ------
// willSet 10
// 1 update
// 0 -> 10
// ------
// willSet 10
// no changes
// ------
// willSet 20
// 2 update
// 10 -> 20
  • Class property
class Car {
    static var count = 0
    var moving = false
    
    func start() {
        Car.count += 1
        moving = true
    }
    
    func stop() {
        if Car.count > 0 {
            Car.count -= 1
            moving = false
        }
    }
}

let car1 = Car()
let car2 = Car()
print("\(Car.count)") // 0
car1.start()
car2.start()
print("\(Car.count)") // 2
car2.stop()
print("\(Car.count)") // 1
  • Computed class propety
class MyClass {
    static var radian:Double = 0.0
    class var degree:Double {
        get {
            return radian * 90/Double.pi
        }
        
        set(dosu){
            radian = dosu * Double.pi/90
        }
    }
}

MyClass.degree = 18
let katamuki = MyClass.degree
print("\(katamuki)") // 18.0

MyClass.radian = Double.pi/2
let katamuki2 = MyClass.degree
print("\(katamuki2)") // 45.0
  • Class method
class Message {
    class func hello() -> String {
        return "hello"
    }
}

let msg = Message.hello()
print(msg)
  • Access Right
    • access rightを省略するとinternalになる。
    • class がfileprivateだと、property/methodをinternalにすることはできない。
    • fileprivate(set) だとfile外からは、read onlyになる
access right ---
open ---
public Inheritanceとoverrideができない。
internal module外からアクセスできない
fileprivate ファイル外からアクセスできない
private class外からアクセスできない
  • Extension
class Player {
    var name:String = ""
    func hello() {
        print("やあ!" + name)
    }
}

extension Player {
    var who:String {
        get {
            return name
        }
        set(value) {
            name = value
        }
    }
    
    func bye() {
        print("good bye " + name)
    }
}

let obj = Player()
obj.who = "sam" // やあ!sam
obj.hello()
obj.bye() // good bye sam
  • Inheritance
    • A classを継承したB classを作成する。
      • A class は、B classのsuperclass
      • B class は、A classのsubclass
      • B class -> A class
      • 1つのclassが直接継承できるclassは一個だけ
---
class ViewController: UIViewController {
---
}
  • Override
    • superclassと同名のメソッドをsubclass側でも定義してメソッドを上書きする
    • superは、superclassのインスタンス, selfは現在のインスタンス自身
override func viewDidLoad() { // superclass のviewDidLoad()を上書き
    super.viewDidLoad() // superclassのメソッドを実行
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
  • final ( 継承を禁止したいclass, override されては困るメソッドに付ける。 )
final class MyClass {
    func hello() {
        print("hello")
    }
}
class MyClass {
    final func hello() {
        print("hello")
    }
}
  • Protocol ( classが必ず実装しなければならないpropertyやmethodを指定した仕様書のようなもの。実装しないとエラーになる。 )
    • 読み書き可能なpropertyには、{get set} をつける
    • protocolは他のprotocolを継承できる
protocol GameProtocol {
    var gamePoint:Int {get}
    func hit()
    func miss()
}

- class MyGame:GameProtocol {
+ class MyGame:GameProtocol { // protocol requires function 'miss()' with type '() -> ()'; do you want to add a stub?
    private var total = 0
    var gamePoint: Int {
        return total
    }
    
    func hit() {
        total += 10
        print("hit! +10")
    }

-    func miss() {
-        total /= 2
-        print("you miss, half")
-    }    
+ //    func miss() {
+ //        total /= 2
+ //        print("you miss, half")
+ //    }
}

let myGameObj = MyGame()
myGameObj.hit() // hit! +10
print(myGameObj.gamePoint) // 10
myGameObj.miss() // you miss, half
print(myGameObj.gamePoint) // 5
myGameObj.hit() // hit! +10
print(myGameObj.gamePoint) // 15
  • Enumeration ( 複数の値を一つの型として宣言するために使用。Swiftの列挙型は値だけではなく、propertyやメソッドを持つことができる。)
enum MensSize {
    case S
    case M
    case L
    case XL
}

enum WomenSize {
    case XS, S, M, L
}

var mySize = MensSize.M
mySize = .S // 型推論で、mySizeは、MensSize型になる

var herSize:WomensSize
herSize = .XS

print(mySize) // S
print(herSize) // XS
enum Direction:Int {
    case forward = 1
    case backword // 2
    case right // 3
    case left  // 4
}

let muki1 = Direction.forward
let muki2 = Direction.backword
let muki3 = Direction.right
let muki4 = Direction.left

print(muki1.rawValue) // 1
print(muki2.rawValue) // 2
print(muki3.rawValue) // 3
print(muki4.rawValue) // 4
let muki5 = Direction(rawValue: 3)
if let muki = muki5 { // muki5はnilかもしれないので、Optional Bindingになっている。
    print(muki)
}
  • Enum で型を列挙する
enum Pattern {
    case Monotone(_:PColor)
    case Border(color1:PColor, color2:PColor)
    case Dots(base:PColor, dot1:PColor, dot2:PColor)

    enum PColor:String {
        case red = "red"
        case green = "緑"
        case yellow = "yellow"
        case white = "白"
    }
}

let shirt1 = Pattern.Monotone(.red)
let shirt2 = Pattern.Border(color1: .white, color2: .red)
let shirt3 = Pattern.Dots(base: .yellow, dot1: .white, dot2: .green)
  • Propertyを持ったEnum
enum Ticket {
    case Gold, A, B
    static var name = "入場券"
    
    var area:String {
        get {
            switch self {
            case .Gold:
                return "Gold sheet"
            case .A:
                return "A sheet"
            case .B:
                return "B sheet"
            }
        }
    }
    
    var price:Int {
        get {
            switch self {
            case .Gold:
                return 24000
            case .A:
                return 5000
            case .B:
                return 2000
            }
        }
    }
}

Ticket.name = "hoge live"
print(Ticket.name) // hoge live
let ticket = Ticket.A
print(ticket) // A
print(ticket.price) // 5000
print(ticket.area) // A sheet
  • Methodを持ったEnum
enum Signal:String {
    case Green = "green"
    case Red = "red"
    
    var color:String {
        return self.rawValue
    }
    
    static func description() -> String {
        return "red or green signal"
    }
    
    func isRun() -> Bool {
        if self == .Green {
            return true
        } else {
            return false
        }
    }
    
    mutating func turn() { // 自身を変更するメソッドには `mutating` をつける必要がある
        if self == .Green {
            self = .Red
        } else {
            self = .Green
        }
    }
}

let text = Signal.description()
print(text)  // red or green signal
var lamp = Signal.Green
print(lamp.color) // green
print(lamp.isRun()) // true
lamp.turn()
print(lamp.color) // red
print(lamp.isRun()) // false
  • Struct ( classと違って継承はできない )
struct Box {
    let width:Int
    let height:Int
    let size:String
    let tanka:Int
    var kosu:Int
    
    var price:Int {
        return tanka*kosu
    }
    
    init(width:Int, height:Int, tanka:Int, kosu:Int){
        self.width = width
        self.height = height
        self.tanka = tanka
        self.kosu = kosu
        
        if (width+height) < 250 {
            size = "M"
        } else {
            size = "L"
        }
    }
    
    func sellprice(nebiki:Int = 0) -> Int {
        return price - nebiki*kosu
    }
    
    mutating func discount(count: Int) {
        kosu -= count
    }
}

var box = Box(width: 120, height: 80, tanka: 700, kosu: 6)
print(box) // Box(width: 120, height: 80, size: "M", tanka: 700, kosu: 6)
let selling_price = box.sellprice(nebiki: 10)
print(selling_price) // 4140
box.discount(count: 5)
print(box) // Box(width: 120, height: 80, size: "M", tanka: 700, kosu: 1)
  • Structのcopy
    • Structはclassのobjectと違って、参照型ではなく、値型
    • つまりvariable aに入っているStructをvariable bに代入すると参照ではなく、値が複製されて新しいStructとして代入される
    • String, Array, DictionaryはStruct、だから参照型ではなく、値型
class BoxClass {
    var color:String = "red"
}

struct BoxStruct {
    var color:String = "red"
}

// class
let cBox1 = BoxClass()
let cBox2 = cBox1
cBox2.color = "green"

// struct
let sBox1 = BoxStruct()
var sBox2 = sBox1
sBox2.color = "green"

print("cbox1: \(cBox1.color)") // green
print("cbox2: \(cBox2.color)") // green
print("sbox1: \(sBox1.color)") // red
print("sbox2: \(sBox2.color)") // green
  • Structのsubscript

  • Struct, subscript

struct Stock {
    var name:String
    var data:[String:Int] = [:]
    init(name:String){
        self.name = name
    }
    
    subscript(color:String, size:Double) -> Int {
        get {
            let key = color + String(size)
            if let value = data[key] {
                return value
            } else {
                return 0
            }
        }
        
        set {
            let key = color + String(size)
            data[key] = newValue
        }
    }
}

var shoes = Stock(name: "Tiger")
shoes["green", 24.5] = 3
shoes["green", 25.0] = 5
shoes["red", 26.0] = 5

print(shoes.name) // Tiger
print(shoes["green", 24.5]) // 3
print(shoes["green", 25.0]) // 5
print(shoes["red", 26.0]) // 5

shoes["green", 24.5] -= 2
print(shoes["green", 24.5]) // 1

print(shoes["black", 24.5]) // 0
  • Structのprotocol
protocol Monster {
    var monsterName:String {get}
    var hp:Int {get set}
    mutating func updateHP(pt:Int)
}

struct Bokemon: Monster {
    private(set) var monsterName: String // propertyがread onlyなので、private(set)を付ける
    var hp: Int
    mutating func updateHP(pt: Int) {
        hp += pt
    }
}

var monster = Bokemon(monsterName: "swifty", hp: 200)
print(monster.monsterName) // swifty
print("HP \(monster.hp)") // 200
monster.updateHP(pt: 30)
print("HP \(monster.hp)") // 230

reference from

https://www.amazon.co.jp/dp/4800711843

Swift ざっくり文法 (3)

  • 関数定義
func dice() -> Int {
    let num = 1 + arc4random_uniform(6)
    return Int(num)
}
 // メソッド定義(戻り値がない関数をメソッドと呼ぶ)
func hello() {
    print("hello")
}

or

func hello() -> Void {
    print("hello")
}
  • guard-else ( 条件を満たさないときに実行される )
func half(num: Double){
-    if (num < 10) {
+    guard num>=10 else {
        return
    }
    let halfNum = num/2
    print("\(num)の半分は\(halfNum)")
}

half(num: 25) // 25.0の半分は12.5
half(num: 9)
half(num: 12) // 12.0の半分は6.0
  • defer statement ( 処理(ブロック)を抜ける前にかならず実行する )
func half(num: Double){
+    defer {
+        print("計算終了")
+    }
    guard num>=10 else {
        return
    }
    let halfNum = num/2
    print("\(num)の半分は\(halfNum)")
}

half(num: 25)
// 25.0の半分は12.5
// 計算終了  
half(num: 9)
// 計算終了 <- half(num: 9)は中断されるが、defer文で書いているので実行される 
half(num: 12)
// 12.0の半分は6.0
// 計算終了
  • 可変長引数
func sum(numbers: Double...) -> Double {
    var total: Double = 0.0
    for num in numbers {
        total += num
    }
    return total
}

print(sum(numbers: 4, 5, 6, 7))
  • default引数
- func pricel(ninzu: Int, tanaka: Int) -> Int {
+ func pricel(ninzu: Int = 1, tanaka: Int = 250) -> Int { 
    let result = tanaka * ninzu
    return result
}

print(pricel(ninzu: 3, tanaka: 1300))
  • Tupleを利用した複数の戻り値
- func pricel(ninzu: Int, tanaka: Int) -> Int {
+ func pricel(ninzu: Int, tanaka: Int, rate: Double) -> (hoge: Int, fuga: Double) {
    let result = tanaka * ninzu
+    let updatedResult = Double(result) * rate
-    return result
+    return (result, updatedResult)
}

- print(pricel(ninzu: 3, tanaka: 1300))
+ print(pricel(ninzu: 3, tanaka: 1300, rate: 1.8).hoge)
  • 関数の多重定義( 同名の関数でも引数名や引数の個数が違うと別の関数として扱われる。)
func calc(a: Int, b: Int) -> Int {
    return a+b
}

func calc (c: Int, d: Int) -> Int {
    return c*d
}

func calc(a: Int, b: Int, c: Int) -> Int {
    return (a+b)*c
}

print(calc(a: 2, b: 3)) // 5
print(calc(c: 2, d: 3)) // 6
print(calc(a: 2, b: 3, c: 4)) // 20
  • 外部引数名
- func pricel(ninzu: Int, tanaka: Int) -> Int {
+ func pricel(hoge ninzu: Int, fuga tanaka: Int) -> Int {
    let result = tanaka * ninzu
    return result
}

- print(pricel(ninzu: 3, tanaka: 1300))
+ print(pricel(hoge: 3, fuga: 1300))
  • 引数名なし
- func pricel(hoge ninzu: Int, fuga tanaka: Int) -> Int {
+ func pricel(_ ninzu: Int, _ tanaka: Int) -> Int {
    let result = tanaka * ninzu
    return result
}

- print(pricel(ninzu: 3, tanaka: 1300))
+ print(pricel(3, 1300))

reference from

https://www.amazon.co.jp/dp/4800711843

Swift ざっくり文法 (2)

  • Tuple ( タプル )
let product: (String, Int) = ("Swift", 2015)
let kingaku = (1000, 80) // 型推論で(Int, Int)に決まる
kingaku = (1060,  "hoge") // error: cannot call value of non-function type '(Int, Int)'
let data = (1000, 80)
let (price, _) = data
print(price)

不要な値は、_ で無視できる。

let data = (1000, 80)
print(data.0)

indexでaccess

let kingaku = (price: 1000, tax: 80)
let seikyuugaku = kingaku.price + kingaku.tax
print(seikyuugaku)

ラベル付け

  • Range

    • ..< 終了値を含まない
    • ... 終了値を含む
  • Bitwise Operators

    • 2進数 接頭辞に 0b
    • 16進数 接頭辞に 0x

    • Bit Shift

      • 指定した方向に桁をシフトする演算( 10進数の数値を左を一桁シフトすると値が10倍になるように2進数の値を左へ1桁シフトすると値が2倍になる。 )
let v: UInt8 = 0b00000101
let v2 = v<<1
print(v, v2) // 5, 10
  • Bitwise operation
演算式 説明
a & b ビット積、各桁を比較し、両方の桁が1ならば1
a b | ビット和、各桁を比較し、どちらかの桁が1ならば1
a ^ b 排他的ビット和、各桁を比較し、片方が1の桁だけ1
~a ビット否定、各桁の1と0を反転

16進数#40E0D0 からビット積とビットシフトを使って、RGBを取り出して、0~255 の値に変換し、さらに255 で割って0~1にしてビューの背景色に指定

    let RGB: UInt32 = 0x40E0D0 // turquoise(64, 224, 208)
    let red = (RGB & 0xFF0000) >> 16 // 上位二桁
    let green = (RGB & 0x00FF00) >> 16 // 中央二桁
    let blue = RGB & 0x0000FF // 下二桁
    
    let R = CGFloat(red)/255
    let G = CGFloat(green)/255
    let B = CGFloat(blue)/255
    view.backgroundColor = UIColor(red: R, green: G, blue: B, alpha: 1)

ビット否定

let v: UInt8 = 0b00001010
let v2 = ~v
print(v, v2) //10 245
  • if statementでは以下のような書き方が可能
- if ((sugaku>=40) && (eigo>=60) && ((suugaku+eigo)>=120)) {
+ if sugaku>=40, eigo>=60, (suugaku+eigo)>=120 {
  • Switch statement
    • swiftのswitch statementは、breakがなくても抜けてくれる。
    • 意図的に処理を次のcase文に渡したい場合は、fallthrough キーワードを書く。

    • value binding

let size = (4, 10)
switch size {
    case (0, 0):
        print("hoge")
    case (5...10, 5...10):
        print("bar")
    case (5...10, let height): //
        print("height:" + "\(height)")
    case (let width, 5...10):
        print("width:" + "\(width)")
    default:
        print("foo")
}

where で、値の振り分けに条件式を使えるようになる。

let size = (45, 40, 100)
switch size {
    case let (width, height, _) where (width>=60) || (height>=60):
        print("hoge")
    case let (_, _, weight) where (weight>=80):
        print("bar")
default:
    print("foo")
}

caseに当てはまらない値があり得る場合には、最後のdefaultは必ず必要だが、caseに当てはまらない値がない場合はdefaultを省略可能

let aPoint = (50, 100)
switch aPoint {
    case (0, 0):
        print("中心点")
    case (0, _):
        print("x軸上の点")
    case (_, 0): //
        print("y軸上の点")
    case (x, y):
        print("点(\(x), \(y))")
}
  • 単に処理を任意の回数繰り返したい時( rubyでいうところの、timesみたいな感じ )
for _ in 1...15 {
    let num = arc4random_uniform(100)
    print(num, terminator:  ",")
}
  • for-in でstringから一文字ずつ取り出す
let message = "ありがとう"
for char in message {
    print(char)
}
// あ
// り
// が
// と
// う
  • 飛び飛びで繰り返す for-in stride()
for num in stride(from: 10, to: 30, by: 3) {
    print(num, terminator: ",")
}
// 10, 13, 16, 19, 22, 25, 28
  • 他の言語で言うところのdo-while は、swiftだとrepeat-while
  • loop ( for-in, while, repeat-while ) には、labelが付けられる
xloop: for x in 0...3 {
    yloop: for y in 0...3 {
        if (x<y) {
            print("------")
            continue xloop // yloopを中断して、xloopに抜ける
        }
        print((x, y))
    }
}
let vlist:Array = [[4, 2], [5], [9, 8, 10], [6, 8, -9], [4, 2], [9, 3]]
outloop: for alist in vlist {
    inloop: for v in alist {
        if v<0 {
            print(alist)
            break outloop // inloop だけでなく、outloopも中断する。
        }
    }
}
  • 複数行のString literal ( swift4から )
"""
swift4
swift3
swift4
"""
  • Array
let colors:[String] = ["red", "blue", "green"]
let hoge:[Any] = ["ed", "bl", 3]
var numList:Array<Int> = [12, 34, 56, 79, 59]
var resultList:Array<Bool>
resultList = [true, false, true, false]

型推論

var stringList = ["foo", "bar", "baz"]
// stringList は、型推論で[String]に設定されているため、それ以外の型を入れようとするとエラー
stringList = [3, 4, 6] // error: cannot convert value of type 'Int' to expected element type 'String'

空のArray

var resultList:Array<Bool>
resultList = []
var resultList = [Bool]()
var resultList = Array<Double>()

Repeating

var stars = String(repeating: "★", count: 7) // "★★★★★★★"
var resultList = Array<Bool>(repeating: true, count: 5) // [true, true, true, true, true]

配列を別の変数に代入すると、変数には配列の参照ではなく、コピー(複製)が作られて入る。

var array1 = [1, 2, 3]
let array2 = array1
// ここまではシャローコピー
array1[0] = 99
// ここでディープコピー
print("array \(array1)")
print("array \(array2)")
  • Copyの種類

    • Shallow Copy
      • 元の配列の参照をコピーしただけで実際には同じ配列を指した別名の配列を作る
    • Deep copy
      • 同じ値をもった完全に新しい別の配列を作る
    • Lazy copy in Swift
      • 配列を一旦Shallow Copyして、配列の要素や値を変更しようとした時点で自動的にDeep copyした新しい配列を作る
  • Set

    • 配列と違ってSetは同じ値を重複して持つことができず、値には順番がない。
let colorSet:Set<String> = ["red", "green", "blue", "green"]
print(colorSet) // ["green", "red", "blue"]
print(type(of: colorSet)) // Set<String>

Array -> Set, Set -> Array

var colorArray = ["red", "green", "blue", "green"]
print(colorArray, type(of: colorArray)) // ["red", "green", "blue", "green"] Array<String>
let colorSet = Set(colorArray)
colorArray = Array(colorSet)
print(colorSet, type(of: colorSet)) // ["blue", "green", "red"] Set<String>
print(colorArray, type(of: colorArray)) // ["blue", "green", "red"] Array<String>
  • 空のSet
var numSet:Set<Int> = []
  • Setに値を追加しても、重複していれば、同じ値は入らない。
var numSet:Set<Int> = []
numSet.insert(3)
numSet.insert(5)
numSet.insert(7)
numSet.insert(9)
numSet.insert(5)
print(numSet) // [5, 7, 3, 9]
  • Closure
let ageArray = [21, 30, 28, 35, 45, 52, 33]
let age30to39 = ageArray.filter({(age: Int) -> Bool in
    return (age>=30)&&(age<40)
})
print(age30to39)
  • dictionary
    • キーは、全てが同じ型で重複しない一意なものでないといけない。
let sizeTable = ["S": 47, "M": 52, "L": 55]
let sizeTable:[String:Int] = ["S": 47, "M": 52, "L": 55]
let sizeTable:Dictionary<String, Int> = ["S": 47, "M": 52, "L": 55]

空のdictionary

let sizeTable:[String:Int] = [:]
let sizeTable = [String:Int]()
let sizeTable = Dictionary<String, Int>()

TupleからDictionaryを作る

let a = ("A", 1)
let b = ("B", 2)
let c = ("C", 3)
let abcDic = Dictionary(dictionaryLiteral: a, b, c)
print(abcDic)

reference from

https://www.amazon.co.jp/dp/4800711843

Swift ざっくり文法 (1)

  • statement

    • 区切りは、; か改行
    • ; 付けないことが一般的
  • print

print("blue", "green", separator: "+", terminator: ",")
print("yellow", terminator: ",")
print("red")
// blue+green,yellow,red
print(#file) // MyPlayground.playground
print(#line) // 16
print(#column) // 7
print(#function) // __lldb_expr_57
  • constant, variable

    --- ---
    constant let
    variable var
    • {} で区切られている範囲がconstant, variableのスコープ
      • class
      • method
      • if statement
let name: String
name = "タナカ"
let name: String = "タナカ"
let name = "タナカ"
  • 演算子の、前後に空白を入れるか/詰めるかしないとError
price = 2500 * rate // ok
price = 2500*rate // ok
price = 2500* rate // error: consecutive statements on a line must be separated by ';'
  • 型判定
let tax = 0.08
print(type(of:tax)) // Double
  • 型変換
let num: Int = 4 // 4
Double(num) // 4.0
  • 文字列中の変数展開
let hoge = 32
print("hoge: \(hoge)")

Reference from

https://www.amazon.co.jp/dp/4800711843

SwiftのOptionalまわりについて

  • Swiftの変数・定数はnilが発生しないようになっていて、nilを代入したい変数は、型をOptional型にする必要がある。
  • String?のように型の後ろに?をつけるとnilを代入できるOptional型にWrapされる
let nums = [3, 4, 6]
let lastNum = nums.last
let ans = lastNum * 2 // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ?
print(ans)

lastNum に数値ではなくnilが入ってる可能性があり、もしnilだった場合、lastNum * 2 が計算できずバグの要因になる可能性がある。したがって、Swiftはこういう場合、エラーを防ぐため、変数・定数にnilが代入されることを黙っては許可しない。

var num:Int
num = 5
num = nil // Nil cannot be assigned to type 'Int'

nilを変数に代入しようとすると上記のようなエラーになる。

- var num:Int
+ var num:Int?
num = 5
- num = nil // Nil cannot be assigned to type 'Int'
+ num = nil
print(num) // nil

OptionalValue とは、nilの可能性がある値のこと。

上記のように、型の後ろに ? を付けることで、numは、OptionalValue を代入できる Optional型の変数になり、num = nil の式はエラーではなくなる。

var num:Int?
num = 5
print(num) // Optional(5)
var num:Int?
num = 5
print(num * 3) // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ?

型に ? を付けて宣言した変数にはnilを代入できることがわかったが、Optional 型の変数にnil以外の値を代入したときには注意が必要

上記の num は、Int型の5が、Optional(Int) のようにWrapされている状態。OptionalValueは、このままでは使えない。

var num:Int?
num = 5
- print(num * 3) // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?' ?
+ print(num! * 3) // 15

Optional(Int) を計算式で使うには、Optional() のラップを取り除く、つまりunwrapする必要がある。

unwrapの最も簡単な方法は、OptionalValue に ! をつけること。

var num:Int?
num = nil
print(num! * 3) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

ただOptionalValueが本当にnilだった場合、強制unwrapするとエラーになる。

var num:Int?
num = nil
if num != nil {
    print(num! * 2)
} else {
    print("num is empty")
}

したがって、上記のようにnumがnilでないか確認する必要がある。 それをSwift側でやってくれるのが、Optional Binding。 Optional Binding とは、Optional Valuenilでなければ値をunwrap して、一時変数に代入し、nilの場合はfalseを返す機能。(if, while, guard-else)

  • if
var str:String?
str = "Swift"
if let msg = str { // Optional Valueがnilでなければ、値をunwrapして一時変数に代入
    print(msg + "world")
} else { //  Optional Valueがnilのときは、else blockが実行される
    print("hello world")
}
  • if-where
let year1:String = "2001"
let year2:String = "2016"

if let startYear = Int(year1), let endYear = Int(year2), startYear < endYear { // year1, year2がnilだった場合、`startYear < endYear` の式は実行されない
    let years = endYear - startYear
    print("\(years)年間") // 15年間
}
  • dictionary
var sum = 0
let dic:[String:Int?] = ["a": 24, "b": nil, "c": 10, "d": nil]

for (_, value) in dic {
    if let num = value {
        sum+=num // dicから順に取り出したvalueがnilでないときだけ実行される
    }
}
print("数値の合計は\(sum)") // 34
  • while
var str:String? = "★"
var repeatString:String = ""
var i = 0

while let stamp = str { // strがnilじゃないときunwrapしてstampに代入。nilならwhileループを実行しない。
    repeatString += stamp
    i += 1
    if(i >= 10) {
        break
    }
}
print(repeatString) // ★★★★★★★★★★
  • guard-else
let who = "さくら"
var level:Int?

func hello() {
    guard let theLevel = level else {
        print("level is nil")
        return
    }
    
    if theLevel<10 {
        print(who+"隊員")
    } else {
        print(who+"上級隊員")
    }
}

hello() // level is nil levelがnilなので、処理が中断されている

level = 5

hello() // サクラ隊員
print(count) // nil
print(count ?? 2) // 2

price = (count ?? 2) * 250
print(price) // 500

count = 3

print(count) // Optional(3)
print(count ?? 2) // 3

price = (count ?? 2) * 250
print(price) // 750

OptionalValueがnilのとき、?? を使うとnilに代わる値を指定できる

var balls:[(size:Int, color:String)] =[]
- var ballSize = balls.first.size // Value of optional type '(size:Int, color:String)?' not unwrapped; did you mean to use '!' or '?' ?
+ var ballSize = balls.first?.size
print(ballSize)  // nil
var balls:[(size:Int, color:String)] =[(size:2, color:"red"), (size:4, color:"green") ]
- var ballSize = balls.first.size // Value of optional type '(size:Int, color:String)?' not unwrapped; did you mean to use '!' or '?' ?
+ var ballSize = balls.first?.size
print(ballSize) // Optional(2)

.でアクセスするときに対象に?をつけることで実行時エラーを回避できる記述方法をOptional chainと呼ぶ

上記だと、Optional型で、値を使うことができず、unwrapする必要があるので、Optional Bindingと組み合わせる。

var balls:[(size:Int, color:String)] =[(size:2, color:"red"), (size:4, color:"green") ]
var ballSize = balls.first?.size
+ if let ballSize = balls.first?.size {
+     print(ballSize) // 2
+ }

reference from

https://www.amazon.co.jp/dp/4800711843

随時更新!! Xcode shortcutまとめ

Xcode

--- shortcut
New Project command + shift + n
New Playground option + command + shift + n
Tool Bar command + option + t
Navigation command + 0
Debug Area shift + command + y
Utility Area command + option + 0
Modify Indentation ctrl + i
Grep File command + shift + o
Utility Area の object library の grep command + option + ctrl + 3
Go Back commad + ctrl + ←
Show Standard Editor command + enter
Show Assistant Editor command + option + enter

Simulator

--- shortcut
Toggle Software keyboard command + k

reference from

https://www.amazon.co.jp/dp/4798048704

随時更新!! AWS S3 cli のよく使うコマンドまとめ

s3にあるオブジェクトの総量を見たい時

$ aws s3 ls --summarize --human-readable --recursive s3://<backet name>

---
Total Objects: 21887
   Total Size: 2.7 GiB

s3にディレクトリを同期

$ aws s3 sync <local path> s3://<s3 backet> --exact-timestamps 

reference from

http://www.task-notes.com/entry/20150904/1441335600 https://docs.aws.amazon.com/cli/latest/reference/s3/index.html