Open35

iOS開発の知識

tishii2479tishii2479

ライフサイクルについて

https://qiita.com/motokiee/items/0ca628b4cc74c8c5599d

ライフサイクル

  • loadView
    カスタムViewの初期化を行う。StoryboardxibなどのInterfaceBuilderを利用しているときはこのメソッドは呼び出さない。
  • viewDidLoad
    viewがロードされた後に呼び出される。
  • viewWillAppear
    viewが表示される直前
  • viewWillLayoutSubviews
    layoutSubViewsの前
  • viewDidLayoutSubviews
    layoutSubViewsの後
  • viewDidAppear
    完全に遷移が完了し、画面上に表示された時に呼ばれる。
  • viewWillDisappear
    viewが表示されなくなる直前で呼ばれる。
  • viewDidDisappear
    完全に遷移が行われ、画面上に表示されなくなった時に呼ばれる。
tishii2479tishii2479

weakunownedstrongについて

https://qiita.com/rockname/items/b00d52c9bc49603f99a5

Swiftのメモリはガベージコレクションでなく、ARC(Automatic Reference Counting)によって管理されている。

ARCとは

それぞれのインスタンスがいくつのプロパティや変数、定数から参照されているかをカウントする。
ゼロになったらメモリを解放し、ゼロにならない限りメモリは解放しない。

strong(強参照)

何も修飾語をつけないと強参照になる。
二つのインスタンスがお互いに強参照し合うと、循環参照を起こす。

weak(弱参照)

ARCの参照カウントに加算されない。
参照対象が自身よりも先にメモリが解放される時に使う。

unowned(非所有参照)

ARCの参照カウントに加算されない。
参照対象が自身と同じか、後にメモリが解放される時に使う。

tishii2479tishii2479

classstructenumの使い分け

https://qiita.com/omochimetaru/items/8827934de3f7662b08a8
https://qiita.com/Howasuto/items/57acf33b40dbf4604397

class

参照型

参照の共有
インスタンスを共有したい時に使う。

struct

値型

コピーオンライトという機能
代入を行なった時点でコピーは行われず、値が異なった時にコピーが行われる。

  • 不必要なコピー作業を省き、パフォーマンスの向上
tishii2479tishii2479

ArraySetDictionaryについて

Array

配列

Set

集合

  • ユニークなデータを保持する
  • 順番は保持されない

オペレーション
intersectionsymmetriceDifferenceunionsubtracting

Dictionary

辞書

tishii2479tishii2479

GDPについて

https://ticklecode.com/swfitgdp/#GDP(Grand_Central_Dispatch)の特徴

GDP(Grand Central Dispatch)

非同期処理を容易にするためのC言語ベースの技術。

  • タスクをキューに追加して非同期処理
  • スレッドを直接管理しない
  • 予め準備された空きスレッドを使う(スレッドプール)

dispatch queue

GDPで用いるキュー。

実行方式

直列、並列の二種類

作り方

main queue

メインスレッドで実行する直列dispatchQueue
ユーザインターフェースの更新は常にmain queueで行う。

let mainQueue = DispatchQueue.main

global queue

並列dispatchQueue
実行優先度を指定して取得

実行優先度

QoS(Quality of Service)という

  • userInteractive
  • userInitiated
  • default
  • utility
  • background

attributes

.concurrentは並列DispatchQueueを生成する時につける。

GDPでは難しいケース

複雑な非同期処理には向かない。

  • 条件に応じたタスクのキャンセル、タスク同士の依存関係の定義など
  • OperationOperationQueueクラスを利用する
tishii2479tishii2479

mutating func

自身の値を変更するときにmutatingキーワードを書く

extension Int {
    mutating func plusOne() {
        self += 1
    }
}

var i: Int = 0
i.plusOne()
print(i)
tishii2479tishii2479

@escaping

https://qiita.com/mishimay/items/1232dbfe8208e77ed10e

引数に受け取るクロージャに対してattributeとして付与する。
クロージャがスコープから抜けても存在し続ける時に必要になる。

  • クロージャがスコープ外で強参照される時
  • クロージャを非同期的に実行するとき
class A {
    private let storedClosure: () -> ()

    init(closure: @escaping () -> ()) {
        storedClosure = closure
    }
}

必要なこと

  • self.が必要
  • [weak self]を使用することで、循環参照を防ぐ
tishii2479tishii2479

defer

  • スコープを抜ける時に実行したい処理を定義する。
  • 複数のdeferを記述した場合は記述した順番の逆順に呼ばれる。
  • breakreturnを使用してスコープを抜けてしまうと呼ばれない。
tishii2479tishii2479

アクセス修飾子の詳細

https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

  • private
  • fileprivate
  • internal
  • public
  • open

private

同スコープ内からのみ呼び出せる。

fileprivate

同ファイル内からのみ呼び出せる。

internal

同モジュール内からのみ呼び出せる

public

別モジュールから呼び出せるが、継承やオーバーライドが不可能

open

別モジュールから呼び出せる。継承やオーバーライドが可能

swiftでreadonlyにするには

private(set)を利用する。

private (set) var name: String = "apple"
tishii2479tishii2479

AutoLayoutについて

https://www.isoroot.jp/blog/2718/

様々な画面サイズの端末でも柔軟に表示することができる仕組み。

なぜAutoLayoutは必要なのか

  • iOS端末は種類が多く、それぞれの画面のサイズが異なる
  • 絶対位置でUI部品を配置してしまうと、画面のサイズの変更に対応できない

コードでAutoLayoutを使用する

https://qiita.com/jamestong/items/47ef1ce3cb81c60326ee

NSLayoutConstraintNSLayoutAnchorを用いる。

NSLayoutAnchorの方が、コード量が少なく、制約も明確に宣言できる。

ライブラリ

SnapKitというラッパーライブラリが便利。

https://rightcode.co.jp/blog/information-technology/swift4-snapkit-takagai

tishii2479tishii2479

Bridging headerについて

XCodeの機能。
SwiftからObjective-Cを呼び出すときに使う。

{Product Module Name}-Bridging-Header.h
#import "Foo.h"

Objective-CからSwiftを呼び出すとき

#import "{Product Module Name}-Swift.h"
tishii2479tishii2479

Swiftのモジュールとは

Swiftにおけるモジュールの定義

  • コードのまとまりの単位。フレームワークやアプリケーションとして作られた一単位のコードのまとまりで、swiftではimportキーワードを用いることでインポートされる。

名前空間

Swiftでは暗黙的な名前空間が用いられている。

名前空間とはソースコード上で冗長な命名規則を用いなくても名前の衝突が起こらないようにし、それを容易に記述できるようにする概念

tishii2479tishii2479

Codable, Encodable, Decodableについて

https://qiita.com/_ha1f/items/bf1aad5ea3e927f59f9d
https://medium.com/doyeona/codable-decodable-encodable-feat-json-5643dc3d7766#

typealias Codable = Decodable & Encodable

Codable

CodableはJSONデータオブジェクトとSwiftのclass, structの相互変換に用いられる。

Decodable

自身をJSONなどの外部表現からオブジェクトにデコードできる型。(bytes から objectへの変換)

Encodable

自身のオブジェクトをJSONなどの外部表現にエンコードできる型。(object から bytesへの変換)

CodingKeys

エンコード・デコードのキーが一致しないときに用いる。
case名をプロパティ名、rawValueをエンコード結果のフィールド名として定義する。

struct Coordinate: Codable {
    var latitude: Double
    var longitude: Double
    var elevation: Double = 0 // default value

    enum CodingKeys: String, CodingKey {
        case latitude = "another_key"
        case longitude
    }
}
tishii2479tishii2479

Result型について

https://qiita.com/koher/items/7e92414082476fb87b76

非同期処理など、エラーが発生する場合に使う。
ある処理を行うときに、それの成否によって処理を変えるために用いる。

Result型

public enum Result<Success, Failure: Error> {
    case success(Success)
    case failure(Failure)
}

throwsとの違い

  • throwsはエラー型を指定できない。
  • ResultManual PropagationthrowsAutomatic Propagation

Manual Propgationguard if switchなど
Automatic Propagationdo try catch

なぜResult型が使われるのか

Automatic Propagationでうまくいかないときがある。

  • エラーを保持して、引数や戻り値として取り回したいとき(非同期処理など)

エラーハンドリング

https://github.com/apple/swift/blob/main/docs/ErrorHandlingRationale.rst

tishii2479tishii2479

inoutについて

関数に値参照渡しするときに使う。

読みだすときには&をつける

func plus(a: inout Int) {
    a += 1
}

var a = 0
plus(&a)
tishii2479tishii2479

予約語を変数名として使う

基本的には使ってはいけないが、どうしても使わなければいけないとき(APIの
JSONのkeyで使われているときなど)に使う

  • バッククォートで囲う
var `open`: String
tishii2479tishii2479

Equatableについて

https://qiita.com/chino_tweet/items/793bccb0384c8460d267

オブジェクト同士の比較を可能であることを保証するプロトコル。

実装は以下のようにする。

struct Fruit: Equatable {
    var name: String
    var emoji: String

    // 自身と同じ型を2つ受け取る静的メソッド
    static func == (lhs: Fruit, rhs: Fruit) -> Bool{
        return lhs.emoji == rhs.emoji
    }
}

Comparable

大小比較ができることを保証するのはComparable

tishii2479tishii2479

Hashableについて

https://engineering.linecorp.com/ja/blog/swift-4-1/

ハッシュ値を提供できることを表すプロトコル。
これに適合する方はDictionarySetの要素として扱うことができる。

struct S: Hashable {
    let v1, v2 : String
    // `Hashable`に適合させるには`var hashValue: Int { get }`が必要です。
    var hashValue: Int {
        return v1.hashValue ^ v2.hashValue
    }
    // `Hashable`は`Equtable`を継承していますので、`==`演算子も必要です。
    // (`hashValue`の一致後に、さらに`==`で同等の値であるか評価します)
    static func ==(lhs: S, rhs: S) -> Bool {
        return lhs.v1 == rhs.v1 &&
            lhs.v2 == rhs.v2
    }
}
tishii2479tishii2479

AnyとAnyObject

http://tiny-wing.hatenablog.com/entry/2015/12/10/180601

AnyObject

全てのクラス型のインスタンスを表すことができる。
struct, enum, closure, tupleは値型なので扱うことはできない。

  • Objective-Cのメソッドとプロパティを使用する場合に使用する。
  • class only protocolの宣言にも使われる

Any

全ての型のインスタンスを表すことができる。

tishii2479tishii2479

delegateとは

デザインパターンの一つ。
あるクラスは、他のクラスのインスタンスに処理を任せることができるもの。

  • ポリフォーフィズム(多態性)の一例
  • プロトコルで定義されたデリゲートメソッドを実行する
  • 委譲先を意識する必要がない
  • 再利用ができる

protocolAnyObjectを継承する

delegateを使うためのprotocolを使用するときはclass-only protocol(参照型)でなければいけない。

  • weakを使った弱参照を行うため
  • weakは参照型にしか使えない
protocol ProtocolDelegate: AnyObject {}
tishii2479tishii2479

conveniencedesignatedrequiredイニシャライザ

https://qiita.com/edo_m18/items/733d8c81fb00942e3167

convenienceイニシャライザ

同一クラスの別のイニシャライザを呼び出すことができる。

designatedイニシャライザ

基本となるイニシャライザ。init() {}

requiredイニシャライザ

サブクラスでの実装が必須となる。

tishii2479tishii2479

StateObjectについて

https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject

StateObjectを持つViewObservableObjectを所有することになる。つまり、最初にオブジェクトを作ったときにはStateObjectを使用する。他のViewから参照するときは、ObservedObjectを使う。

The rule is this: whichever view is the first to create your object must use @StateObject, to tell SwiftUI it is the owner of the data and is responsible for keeping it alive. All other views must use @ObservedObject, to tell SwiftUI they want to watch the object for changes but don’t own it directly.