20200624のSwiftに関する記事は6件です。

iOS app の習得日記

udemy の講座をみながら、
firebase Authを使って、facebookログインの二週目

ViewControllerに

import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FacebookCore
import FacebookLogin
import Firebase

なぜか?
https://developers.facebook.com/docs/facebook-login/ios
https://firebase.google.com/docs/auth/ios/facebook-login?authuser=0
公式ドキュメントにはこう書いてないのに??

SDKの種類
CoreKit とCoreの違いは??

公式のドキュメントの理解が追いついていない

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WWDC2020で追加された LazyVGrid / LazyHGrid について考察してみる

※注意
- Xcode 12 beta の環境で動作確認したものです。正式版では動作が変わる可能性もあります。
- 今 Swift や iOS 8 について書くのは NDA 違反か調べてみたと同じ考えのもと、Appleが公開する画像・動画・コードおよびその拡張コードの添付は、問題ないと考えています。
- 本記事に出てくる画面スクリーンショットは、全てXcode11.5およびiOS13で再現した画面です。(Xcode12 betaおよびiOS14のものは1つもありません)

はじめに

WWDC2020が初まり、興奮さめやらぬ人も多いのではないでしょうか。
Xcode12 Betaの配布も始まり、公式サイトではいろんなAPIリファレンスが一気に展開されました。

前回のWWDC2019で注目を集めたSwiftUIですが、まだ課題も多くアップデートに期待がかかっていましたが。。
無事に、今回の発表で多くのAPIが追加されたようです!

その中でも、LazyVGrid / LazyHGrid についてフォーカスしてみました。

LazyVGrid / LazyHGrid

WWDC2020の映像でも公開されていましたが、SwiftUI上でのグリッドデザインを、下記のように簡単に作成できるようになりました。

grid example

(Quote: WWDC2020 - What's new in SwiftUI / 10:11~

1. Documentation

まずは公式のドキュメントから覗いてみます。

スクリーンショット 2020-06-24 17.15.39 2.png

(Quote: Documentation - LazyVGrid

名前で予想はついたかと思いますが、それぞれ縦方向・横方向にグリッドを組める仕組みが用意されています。
また、それぞれに同じ記載のあるこの部分

The grid is “lazy,” in that the grid view does not create items until they are needed.

必要になるまでViewの生成がなされないようです。
こちらに関しては後で説明していきます。

2. Code Example

まずは簡単な例をみてもらうのが、一番わかりやすいかと思います。
今回はLazyVGridで例を作成しました。
※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 15.18.10.png

  • Xcode11.5で同じ画面を再現したコード
ScrollView {
    ForEach((0...24), id: \.self) { row in
        HStack {
            ForEach((1...4), id: \.self) { column in
                Text("\(row*4+column)")
                    .frame(width: 80, height: 60) // widthは目視で同じになるように任意の値を設定
            }
        }.frame(maxWidth: .infinity)
    }
}
  • LazyVGridを使用したコード
ScrollView {
    LazyVGrid(columns: Array(repeating: GridItem(), count: 4)) { // カラム数の指定
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
                .frame(width: 60, height: 60)
        }
    }
}

columnsにあるGridItemの数だけ、カラムが生成されます。

以前はForEachStackを用いて、再現したいグリッド部分を入れ子にすることで画面を構成する必要がありました。
LazyVGridでは指定したcolumns数で区切ってくれるようになり、コードもすっきりしてだいぶ明示的になったのではないでしょうか?

3. GridItem

Documentation

先ほどのコードにも記載ありましたが、LazyVGrid/LazyHGridで画面を構成するためには、必ずGridItemを渡してあげる必要があります。

スクリーンショット 2020-06-24 17.56.19.png

(Quote: Documentation - GridItem)

プロパティを見ても分かる通り、レイアウトの調整に使用します。
イメージとしては、UICollectionViewのLayoutに近いと思います。

Variable

このGridItemを使うことで、可変のグリッドも作り出すことが可能です。
GridItemを生成する際の引数としてGridItem.Sizeを指定することで可能になります。
また、サイズの最小値・最大値の設定もこちらで行います。

スクリーンショット 2020-06-24 19.49.24.png

基本的には上記の3タイプで、ざっくり説明すると

① fixed    : グリッドのサイズを固定で設定
② flexible : グリッドのサイズを最小値〜最大値で設定
③ adaptive : グリッドのサイズを最小値〜最大値で設定し、アイテムを詰めて設置

になります。

ぞれぞれ具体例を見ていきましょう。

① fixed

※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 20.43.17.png

Xcode11.5でほぼ同じ画面を再現したコードはこちら
ScrollView {
    ForEach((0...24), id: \.self) { row in
        HStack {
            Text("\(row*4)").frame(width: 10, height: 60)
            Text("\(row*4+1)").frame(width: 30, height: 60)
            Text("\(row*4+2)").frame(width: 20, height: 60)
        }.frame(maxWidth: .infinity)
    }
}

ScrollView {
    LazyVGrid(columns: [GridItem(.fixed(10)), GridItem(.fixed(30)), GridItem(.fixed(20))]) { // GridItemが3つなので3カラム
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

各columnごとに固定値を設定できるようになっています。

② flexible

「① fixed」が可変になった形です。

ScrollView {
    LazyVGrid(columns: [GridItem(.flexible(minimum: 30, maximum: 100)), GridItem(.flexible(minimum: 0, maximum: 10))]) { // GridItemが2つなので2カラム
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

各columnごとに最小値最大値を設定できるようになっています。

③ adaptive

※こちらは既存のもので再現できなかったので、できることのイメージ画像を添付します。
Quote: UICollectionViewでタグが左寄せに並んでいるようなレイアウトを実現する

スクリーンショット 2020-06-24 20.43.17.png

ScrollView {
    LazyVGrid(columns: [GridItem(.adaptive(minimum: 100, maximum: 200))]) {
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

1つ設定するだけで、設定した最小値〜最大値でアイテムを詰めて表示してくれるようになります。
複数のadaptiveを設定した場合はOS側がよしなに分割するようです(何回か試したがそんな感じだった)

4. Lazy

「1. Documentation」で説明しなかったこの部分

The grid is “lazy,” in that the grid view does not create items until they are needed.

このViewはLazyがついていることにすごく意味があります。
それは画面の呼び出しタイミングが違うということです。

下記のコードを、それぞれ新・旧のSwiftUIのコードに追加して、挙動の違いを確認していきたいと思います。

.onAppear {
    debugPrint("onAppear: \(/* current index */)")
}
.onDisappear {
    debugPrint("onDisappear: \(/* current index */)")
}

onAppear/onDisappearを用いて画面の表示・非表示のタイミングでログを出すようにします。

Xcode11.5で同じ画面を再現したコードのログを取得する

スクリーンショット 2020-06-24 18.08.50.png

今までのグリッド実装の場合、画面生成と共にすべてのindexが取得されました。
つまり、画面生成と共にすべての画面(Text)が呼び出されていると言うことになります。

LazyVGridを使用したコードのログを取得する

既存のListと同じ動きをします。
つまり、アイテムが表示されたタイミングonAppearが発火し、非表示になったタイミングでonDisappearが発火します。

スクリーンショット 2020-06-24 18.33.23.png

(画像はイメージ図。Xcode11.5より)

実際の開発においては、複雑なViewが膨大に並ぶことになるかと思います。
そのため、古い実装ではパフォーマンスとして良くないため実戦投入には不向きでした。
その部分において、Gridを使用してパフォーマンスの改善をすることができそうです。

5. PinnedScrollableViews

名前からなんとなく想像がつきそうな、つかなそうなと言う感じですが、
セクションヘッダー・セクションフッターを固定するかどうか指定するためのプロパティになります。

スクリーンショット 2020-06-24 17.50.13.png

(Quote: Documentation - PinnedScrollableViews)

試しにヘッダーを固定したものを用意しました。
※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 19.17.37 2.png

ScrollView {
    LazyVGrid(columns: Array(repeating: GridItem(), count: 4), pinnedViews: .sectionHeaders) { // 固定する方を指定
        Section(header: Text("header")) { // セクション
            ForEach((1...100), id: \.self) { index in
                Text("\(index)")
                    .frame(width: 60, height: 60)
            }
        }
    }
}

引数に追加するだけでとても簡単です。
イメージとしては、UICollectionElementKindSection Header/Footerに近いと思います。
この引数を指定しない場合は、セクションはそのままスクロールされてしまいます。

終わりに

今までのSwiftUIではUICollectionViewに相当するものがなかったため、開発においてハック的なやり方で、だいぶ無理をする必要がありました。
今回フォーカスしたGridで完全に補えているかどうかは怪しいところですが。。。

WWDC2020の発表から、SwiftUIのAPIがたくさん増えたことで、開発の幅が広がりました。
一部の機能はSwiftUIでしか開発できないことを鑑みても、ここ2・3年でSwiftUIへ移行はmustになってきそうです。

間違いがあるかもしれないので、指摘あればお願いしますmm

その他

リポジトリ
- SwiftUI_LazyGrid

ドキュメント
- Documentation - LazyHGrid
- Documentation - LazyVGrid
- Documentation - GridItem
- Documentation - GridItem.Size

外国の方がGridのレイアウトを解説している動画
- Building Grids in SwiftUI 2.0 for iOS 14

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] WWDC2020で追加された LazyVGrid / LazyHGrid について考察してみる

※注意
- Xcode 12 beta の環境で動作確認したものです。正式版では動作が変わる可能性もあります。
- 今 Swift や iOS 8 について書くのは NDA 違反か調べてみたと同じ考えのもと、Appleが公開する画像・動画・コードおよびその拡張コードの添付は、問題ないと考えています。
- 本記事に出てくる画面スクリーンショットは、全てXcode11.5およびiOS13で再現した画面です。(Xcode12 betaおよびiOS14のものは1つもありません)

はじめに

WWDC2020が初まり、興奮さめやらぬ人も多いのではないでしょうか。
Xcode12 Betaの配布も始まり、公式サイトではいろんなAPIリファレンスが一気に展開されました。

前回のWWDC2019で注目を集めたSwiftUIですが、まだ課題も多くアップデートに期待がかかっていましたが。。
無事に、今回の発表で多くのAPIが追加されたようです!

その中でも、LazyVGrid / LazyHGrid についてフォーカスしてみました。

LazyVGrid / LazyHGrid

WWDC2020の映像でも公開されていましたが、SwiftUI上でのグリッドデザインを、下記のように簡単に作成できるようになりました。

grid example

(Quote: WWDC2020 - What's new in SwiftUI / 10:11~

1. Documentation

まずは公式のドキュメントから覗いてみます。

スクリーンショット 2020-06-24 17.15.39 2.png

(Quote: Documentation - LazyVGrid

名前で予想はついたかと思いますが、それぞれ縦方向・横方向にグリッドを組める仕組みが用意されています。
また、それぞれに同じ記載のあるこの部分

The grid is “lazy,” in that the grid view does not create items until they are needed.

必要になるまでViewの生成がなされないようです。
こちらに関しては後で説明していきます。

2. Code Example

まずは簡単な例をみてもらうのが、一番わかりやすいかと思います。
今回はLazyVGridで例を作成しました。
※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 15.18.10.png

  • Xcode11.5で同じ画面を再現したコード
ScrollView {
    ForEach((0...24), id: \.self) { row in
        HStack {
            ForEach((1...4), id: \.self) { column in
                Text("\(row*4+column)")
                    .frame(width: 80, height: 60) // widthは目視で同じになるように任意の値を設定
            }
        }.frame(maxWidth: .infinity)
    }
}
  • LazyVGridを使用したコード
ScrollView {
    LazyVGrid(columns: Array(repeating: GridItem(), count: 4)) { // カラム数の指定
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
                .frame(width: 60, height: 60)
        }
    }
}

columnsにあるGridItemの数だけ、カラムが生成されます。

以前はForEachStackを用いて、再現したいグリッド部分を入れ子にすることで画面を構成する必要がありました。
LazyVGridでは指定したcolumns数で区切ってくれるようになり、コードもすっきりしてだいぶ明示的になったのではないでしょうか?

3. GridItem

Documentation

先ほどのコードにも記載ありましたが、LazyVGrid/LazyHGridで画面を構成するためには、必ずGridItemを渡してあげる必要があります。

スクリーンショット 2020-06-24 17.56.19.png

(Quote: Documentation - GridItem)

プロパティを見ても分かる通り、レイアウトの調整に使用します。
イメージとしては、UICollectionViewのLayoutに近いと思います。

Variable

このGridItemを使うことで、可変のグリッドも作り出すことが可能です。
GridItemを生成する際の引数としてGridItem.Sizeを指定することで可能になります。
また、サイズの最小値・最大値の設定もこちらで行います。

スクリーンショット 2020-06-24 19.49.24.png

基本的には上記の3タイプで、ざっくり説明すると

① fixed    : グリッドのサイズを固定で設定
② flexible : グリッドのサイズを最小値〜最大値で設定
③ adaptive : グリッドのサイズを最小値〜最大値で設定し、アイテムを詰めて設置

になります。

ぞれぞれ具体例を見ていきましょう。

① fixed

※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 20.43.17.png

Xcode11.5でほぼ同じ画面を再現したコードはこちら
ScrollView {
    ForEach((0...24), id: \.self) { row in
        HStack {
            Text("\(row*4)").frame(width: 10, height: 60)
            Text("\(row*4+1)").frame(width: 30, height: 60)
            Text("\(row*4+2)").frame(width: 20, height: 60)
        }.frame(maxWidth: .infinity)
    }
}

ScrollView {
    LazyVGrid(columns: [GridItem(.fixed(10)), GridItem(.fixed(30)), GridItem(.fixed(20))]) { // GridItemが3つなので3カラム
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

各columnごとに固定値を設定できるようになっています。

② flexible

「① fixed」が可変になった形です。

ScrollView {
    LazyVGrid(columns: [GridItem(.flexible(minimum: 30, maximum: 100)), GridItem(.flexible(minimum: 0, maximum: 10))]) { // GridItemが2つなので2カラム
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

各columnごとに最小値最大値を設定できるようになっています。

③ adaptive

※こちらは既存のもので再現できなかったので、できることのイメージ画像を添付します。
Quote: UICollectionViewでタグが左寄せに並んでいるようなレイアウトを実現する

スクリーンショット 2020-06-24 20.43.17.png

ScrollView {
    LazyVGrid(columns: [GridItem(.adaptive(minimum: 100, maximum: 200))]) {
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
        }
    }
}

1つ設定するだけで、設定した最小値〜最大値でアイテムを詰めて表示してくれるようになります。
複数のadaptiveを設定した場合はOS側がよしなに分割するようです(何回か試したがそんな感じだった)

4. Lazy

「1. Documentation」で説明しなかったこの部分

The grid is “lazy,” in that the grid view does not create items until they are needed.

このViewはLazyがついていることにすごく意味があります。
それは画面の呼び出しタイミングが違うということです。

下記のコードを、それぞれ新・旧のSwiftUIのコードに追加して、挙動の違いを確認していきたいと思います。

.onAppear {
    debugPrint("onAppear: \(/* current index */)")
}
.onDisappear {
    debugPrint("onDisappear: \(/* current index */)")
}

onAppear/onDisappearを用いて画面の表示・非表示のタイミングでログを出すようにします。

Xcode11.5で同じ画面を再現したコードのログを取得する

スクリーンショット 2020-06-24 18.08.50.png

今までのグリッド実装の場合、画面生成と共にすべてのindexが取得されました。
つまり、画面生成と共にすべての画面(Text)が呼び出されていると言うことになります。

LazyVGridを使用したコードのログを取得する

既存のListと同じ動きをします。
つまり、アイテムが表示されたタイミングonAppearが発火し、非表示になったタイミングでonDisappearが発火します。

スクリーンショット 2020-06-24 18.33.23.png

(画像はイメージ図。Xcode11.5より)

実際の開発においては、複雑なViewが膨大に並ぶことになるかと思います。
そのため、古い実装ではパフォーマンスとして良くないため実戦投入には不向きでした。
その部分において、Gridを使用してパフォーマンスの改善をすることができそうです。

5. PinnedScrollableViews

名前からなんとなく想像がつきそうな、つかなそうなと言う感じですが、
セクションヘッダー・セクションフッターを固定するかどうか指定するためのプロパティになります。

スクリーンショット 2020-06-24 17.50.13.png

(Quote: Documentation - PinnedScrollableViews)

試しにヘッダーを固定したものを用意しました。
※スクリーンショットはXcode11.5で同じ画面を再現したものです

スクリーンショット 2020-06-24 19.17.37 2.png

ScrollView {
    LazyVGrid(columns: Array(repeating: GridItem(), count: 4), pinnedViews: .sectionHeaders) { // 固定する方を指定
        Section(header: Text("header")) { // セクション
            ForEach((1...100), id: \.self) { index in
                Text("\(index)")
                    .frame(width: 60, height: 60)
            }
        }
    }
}

引数に追加するだけでとても簡単です。
イメージとしては、UICollectionElementKindSection Header/Footerに近いと思います。
この引数を指定しない場合は、セクションはそのままスクロールされてしまいます。

終わりに

今までのSwiftUIではUICollectionViewに相当するものがなかったため、開発においてハック的なやり方で、だいぶ無理をする必要がありました。
今回フォーカスしたGridで完全に補えているかどうかは怪しいところですが。。。

WWDC2020の発表から、SwiftUIのAPIがたくさん増えたことで、開発の幅が広がりました。
一部の機能はSwiftUIでしか開発できないことを鑑みても、ここ2・3年でSwiftUIへ移行はmustになってきそうです。

間違いがあるかもしれないので、指摘あればお願いしますmm

その他

リポジトリ
- SwiftUI_LazyGrid

ドキュメント
- Documentation - LazyHGrid
- Documentation - LazyVGrid
- Documentation - GridItem
- Documentation - GridItem.Size

外国の方がGridのレイアウトを解説している動画
- Building Grids in SwiftUI 2.0 for iOS 14

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Custom URL Schemeを便利に使うためのStruct

Custom URL SchemeのURL文字列をSwift上で使用できるようにパースするための構造体を考えたのでメモ。

想定URL形式: someApp://home/articleDetail?userId=100&articleId=200&searchText=hoge

Custom URL Scheme自体の実装はこちらを参照。
Custom URL Schemeでアプリ内の任意のページを表示する

// DeepLinkHierarchy.swift

struct DeepLinkHierarchy {
    enum TabType: String {
        case home // ※サンプルケース
        case article // ※サンプルケース
        case setting // ※サンプルケース
        case myPage // ※サンプルケース
        case none // ※サンプルケース
    }

    enum ScreenNameType: String {
        case articleDetail
        case archive
        case changeAccount
        case none
    }

    var tabType: TabType
    var screenNameType: ScreenNameType
    var query: DeepLinkQuery

    init(host tabText: String, query queryText: String) {
        tabType = TabType(rawValue: tabText) ?? .none
        screenNameType = ScreenNameType(rawValue: path) ?? .none
        query = DeepLinkQuery(queryText)
    }
}

struct DeepLinkQuery {
    var userId: Int? // ※サンプルプロパティ
    var articleId: Int? // ※サンプルプロパティ
    var searchText: String? // ※サンプルプロパティ

    init(_ query: String) {
        if let userIdText = query.getValue(by: "userId") {
            userId = Int(userIdText)
        }
        if let articleIdText = query.getValue(by: "articleIdText") {
            articleId = Int(articleIdText)
        }
        searchText = query.getValue(by: "searchText")
    }
}

private extension String {
    func getValue(by key: String) -> String? {
        return components(separatedBy: "&")
            .map({ $0.components(separatedBy: "=") })
            .first(where: { $0.first == key })?[1]
    }
}

TabTypeと命名しているのは、UITabBarを利用している前提のもと、どのタブをルートとしておくかの判定に利用する想定とした。
また、ルートタブを指定しつつ、遷移先画面をScreenNameTypeで判別する。

// AppDelegate.swift

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        let deepLinkHierarchy = DeepLinkHierarchy(host: url.host ?? "", query: url.query ?? "")
        print("tabType: \(deepLinkHierarchy.tabType)")
        print("UserId: \(deepLinkHierarchy.query.userId)")
        print("articleId: \(deepLinkHierarchy.query.articleId)")
        print("searchText: \(deepLinkHierarchy.query.searchText)")
        return true
    }

ログアウトプット

tabType: home
UserId: Optional(100)
articleId: Optional(200)
searchText: Optional("hoge")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タイマーアプリをリファクタリングする

はじめに

iPhoneアプリ開発集中講座にあるタイマーアプリのリファクタリングに挑戦してみたいと思います。

楽器アプリの「Day 1 Lesson 4-4 ステップアップ リファクタリングで見通しを改善しよう」(P.165) で学びましたね。タイマーアプリが完成してからでかまいませんので、楽器アプリで学んだことを思い出して、コードの冗長性をなくしてみてください。
(iPhoneアプリ開発集中講座 P.257より引用)

リファリングとは

Twitterのツイートを引用しますが、ソフトウェア開発の上で読みづらくなったコードを整理して可読性の向上と勘違いによる不具合発生の防止が主な目的となると思います。

実際に考えてみる

まずどんな構造にするのか?

タイマアプリは、下記のような用件があると思います

  1. タイマーカウントダウン
  2. タイマーのカウントダウンする設定値を読み出し
  3. タイマーのカウントダウンする設定値の書き込み
  4. UIの表示

4つほどあると思います。

そこでファイルを分けることを考えます。下記のように分けてみました。

用件 ファイル メモ
タイマーカウントダウン CountDownManager.swift(新規) タイマーのカウントダウンを検討する
タイマーのカウントダウンする設定値を読み出し SettingManager.swift(新規) UserDefaultsの読み出しを行う
タイマーのカウントダウンする設定値の書き込み SettingManager.swift(新規) UserDefaultsの読み出しと、取りうる値を管理する
UIの表示 ViewController.swift
SettingViewController.swift
従来のファイルのままとする

スクリーンショット 2020-06-30 15.11.30.png

これから紹介するコードはこちらのgithubに公開しますので参考にしてください。

タイマーカウントダウン

タイマーカウントダウンするTimerManager.swiftを作りました。

課題となるのは、1秒毎にタイムアウトしたときにViewController.swiftにどのように通知するか?です。そこで今回はdelegateを用いてUI表示更新してみることにしました。

下記のようにdelegateメソッドを定義しています。

protocol TimerManagerDelegate: class {
    func timerInterrupt(remainCount:Int)
}

また、いくつかのメソッドを定義しました。

メソッド名 概要
start タイマーカウントダウンを開始する
stop タイマーカウントダウンを停止する
clear タイマーの設定値などを変わった時にクリアする

また、外部公開する変数(プロパティー)を1つ定義しました。

変数名 概要
timerValue タイマーの設定時間

設定値を管理する

設定値を管理するSettingManager.swiftを作りました。

UIPickerViewで表示する設定の選択肢のリストと、タイマーの設定値の取得と設定する変数(プロパティー)を定義しました。

変数名 概要
setttingArray UIPickerViewで表示する設定の選択肢のリスト
timerVaue タイマーの設定時間
UserDefaultsから値を取得、設定する
設定するときは、TimerManager.swiftに設定値を更新して、クリアをする

起動

アプリが起動する時にタイマーカウントダウンするTimerManager.swiftのtimerValueを初期化する処理を追加しました。

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        // タイマーマネージャーのインスタンス取得
        let timerManager = TimerManager.shared
        // 設定マネージャーのインスタンス取得
        let settingManager = SettingManager.shared
        // 設定マネージャーで保持している設定時間をタイマーマネージャーに渡す
        timerManager.timerValue = settingManager.timerVaue
        return true
    }

終わりに

様々なリファクタリングがあると思います。

まずは一例として捉えていただければと思います。ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift]複数の要素を配列から削除する方法

背景

SwiftとFirebaseを使ってマッチングアプリを作っていたところ、不正ユーザーをブロックする機能を実装する必要が出てきました。

そして、タイトルにもあるように、「配列から複数の要素を削除する方法」が必要になったのでその方法を自分なりに考えてみました。

方針

array1からarray2と重複する要素を除去します。

実際の環境では、自分以外の全ユーザーのドキュメントIDをDBから取得して配列(array1)とし、ブロックしたユーザーのドキュメントIDをDBから取得して配列(array2)として、array1からarray2の要素を除去することで、ブロックしていないユーザーのドキュメントIDからなる配列を取得します。

具体的な方法

var array1 = ["a","b","c","d","e","f"]
var array2 = ["a","d","e"]

var duplicateIndexs:[Int] = []

var count = 0

for i in 0..<array1.count {
    if array2.contains(array1[i]){
        duplicateIndexs.append(i)
    }
}

print(duplicateIndexs) // [0, 3, 4]

for i in 0..<duplicateIndexs.count{
    array1.remove(at: duplicateIndexs[i] - count)
    count += 1
}
print(array1) // ["b", "c", "f"]

補足

duplicateIndexsとか、countとかなんかごちゃごちゃやっているなという感じですが、
単に以下のコードだとIndex out of rangeのエラーが出ます。

var array1 = ["a","b","c","d","e","f"]
var array2 = ["a","d","e"]

for i in 0..<array1.count {
    if array2.contains(array1[i]){
        array1.remove(at: i)
    }
}
print(array1)

removeで除去しつつfor文を回しているので、array1が短くなっていき(要素が減っていき)、array1[i]の部分がIndex out of rangeになるんですね。

このエラーを避けるために、duplicateIndexsとか、countとか用意してなんとか目的の、array2の要素を除去した新たな配列を取得することに成功しました。

「もっと他にいい実装方法あるよ」という意見やアドバイスをいただけると幸いです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む