20201026のSwiftに関する記事は12件です。

クロージャー を理解をしよう!

今回は、クロージャー について学習したので、アウトプットしていきます
※以下の内容は、学習内容のアウトプット用のため、誤りがある場合があります。予めご了承ください

クロージャーとは?

クロージャー とは、再利用可能なひとまとまりの処理のことをいいます。
関数はクロージャーの1種であるため、共通の使用が数多くあります。
関数を使用するには、「func」キーワードによる定義が必要でしたが、クロージャーはクロージャー 式という定義方法があります。

関数について復習したい方はこちら!!
関数を理解しよう!( https://qiita.com/syunta061689/items/77e8aa76070a734f1b4d

基本的な定義の方法は以下の通りです。

qiita.rbvar
{(引数名1 , 引数名2 ...) -> 戻り値の型 in 
  クロージャーの実行時に実行される文 
  必要に応じてreturn文で戻り値を返却する
}

次に簡単な例を見ていきましょう。

qiita.rbvar
let double = {(x:Int) -> Int in

return x * 5

}
double(5) //25

引数と戻り値の型の記述は関数と同様ですが、戻り値の型と文はinキーワードで区切ります。
上記の例では、Int型の引数を1つ取り、それを5倍にしたInt型の戻り値を返すクロージャーを定義して実行しています。

クロージャーとしての関数

qiita.rbvar
func rectangleArea(height:Int,width:Int) -> Int {
 let result = height*width
 return result //計算結果を戻す

}

let area = rectangleArea(height: 5,width: 6) //30

上記の例では、変数の型はInt -> Intと明確に決まっており、計算結果のresult returnを実行し,戻り値を返却しています。

クロージャー としてのArray型

次は、配列または、辞書を返すよう:にするパターンです。

Array型について復習したい方はこちら!!
Array型を理解しよう!(https://qiita.com/syunta061689/items/89e549f4a3254f635ce1

簡単な例を見ていきましょう。

qiita.rbvar
func a(num: [Int] -> [Int] { // Int型な配列を返します
    print num
}

func b(strings: [String: Int]) -> [String: Int]{ // キーがString型、値がInt型な辞書を受け取れるようにします。
    print strings
}

let test = a(num:0,1,2) 
let test1 = b(String:[チンパンジー:0,ゴリラ:1]) 

print(a)//[0,1,2]
print(b) //[チンパンジー:0,ゴリラ:1]

最後に

今回は、クロージャーについての基礎をまとめました。しかし、今回記述した内容は基礎中の基礎で、クロージャーは奥深く、複雑な書き方があるのでそこの理解もしっかり今後も行っています。

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

Safariのタブのように動くライブラリを作ってみた

実装イメージ

コード

Podfile
pod 'TDTabView'
ViewController
class ViewController: TDTabViewController {

    var vc1: UIViewController!
    var vc2: UIViewController!
    var vc3: UIViewController!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self

        let storyboard1 = UIStoryboard(name: "Table", bundle: nil)
        vc1 = storyboard1.instantiateInitialViewController()

        let storyboard2 = UIStoryboard(name: "Image", bundle: nil)
        vc2 = storyboard2.instantiateInitialViewController()

        let storyboard3 = UIStoryboard(name: "Web", bundle: nil)
        vc3 = storyboard3.instantiateInitialViewController()
    }
}

extension ViewController: TDTabViewControllerDelegate {
    func viewControllers() -> [UIViewController] {
        return [vc1, vc2, vc3]
    }

    func backgroundColor() -> UIColor? {
        return UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 0.8)
    }
}

ポイント

class ViewController: TDTabViewController {

TDTabViewControllerを継承したViewControllerを作成します。

extension ViewController: TDTabViewControllerDelegate {
    func viewControllers() -> [UIViewController] {
        return [vc1, vc2, vc3]
    }

    func backgroundColor() -> UIColor? {
        return UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 0.8)
    }
}

TDTabViewControllerDelegateを追加して、タブとして表示させたいViewControllerを返すだけ!とってもかんたん!

自作ライブラリを作ってみての感想

主な機能は1日でできたのですが、UIに納得がいかず(まだ改善したいところはありますが)、UI改善に2週間ぐらいかかってしまいました。。。

よかったら使ってあげてください!そしてLGTMをください(*´-`)

gitはこちら
https://github.com/ymarui/TDTabView

おわり

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

Safariのタブのように動くライブラリを作ってみた!!

実装イメージ

コード

Podfile
pod 'TDTabView'
ViewController
class ViewController: TDTabViewController {

    var vc1: UIViewController!
    var vc2: UIViewController!
    var vc3: UIViewController!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self

        let storyboard1 = UIStoryboard(name: "Table", bundle: nil)
        vc1 = storyboard1.instantiateInitialViewController()

        let storyboard2 = UIStoryboard(name: "Image", bundle: nil)
        vc2 = storyboard2.instantiateInitialViewController()

        let storyboard3 = UIStoryboard(name: "Web", bundle: nil)
        vc3 = storyboard3.instantiateInitialViewController()
    }
}

extension ViewController: TDTabViewControllerDelegate {
    func viewControllers() -> [UIViewController] {
        return [vc1, vc2, vc3]
    }

    func backgroundColor() -> UIColor? {
        return UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 0.8)
    }
}

ポイント

class ViewController: TDTabViewController {

TDTabViewControllerを継承したViewControllerを作成します。

extension ViewController: TDTabViewControllerDelegate {
    func viewControllers() -> [UIViewController] {
        return [vc1, vc2, vc3]
    }

    func backgroundColor() -> UIColor? {
        return UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 0.8)
    }
}

TDTabViewControllerDelegateを追加して、タブとして表示させたいViewControllerを返すだけ!とってもかんたん!

自作ライブラリを作ってみての感想

主な機能は1日でできたのですが、UIに納得がいかず(まだ改善したいところはありますが)、UI改善に2週間ぐらいかかってしまいました。。。

よかったら使ってあげてください!そしてLGTMをください(*´-`)

gitはこちら
https://github.com/ymarui/TDTabView

おわり

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

【第一回】初心者二人で0から麻雀アプリ開発

【第二回】→多分一週間後

はじめに

麻雀狂い二人がプログラミング経験ほぼ0からiOSアプリ開発に挑戦する様子を投稿していきます。
以下の内容を主眼に記事を作成します。

  • 学んだこと
  • 詰まったこと
  • 考えたこと

改版履歴

2020/10/26 投稿
2020/10/27 メンバーリンク追加

立ち上げ会議

麻雀アプリ作ろうぜ!!
iPhoneユーザーだからiOSアプリやな!!

                  完

二人で開発を決めた時はこんなもんだったので、改めて立ち上げ会議を行いました。

会議では以下の事項について話し合いました。

  1. どんなアプリにするか
  2. 何の言語で開発するか
  3. 開発のためにどんなツールが必要か
  4. プロジェクトの運営について

何を準備すれば良いかすら分からず、ぶっつけで会議したら案の定ぐだぐだになりました……
事前準備、まじ大事。

どんなアプリにするか

なんか麻雀に関連したアプリ

→日々の成績等を記録する機能
→メンバー内で記録を共有する機能

とりあえず、収支表アプリ的なものを作ろうってことになりました。

アプリを入れたメンバー同士で記録の共有とかできたらいいねーという話。
↑難易度むちゃくちゃ高そう(無知)なので余裕あったら実装

何の言語で開発するか

調査()によると、iOSアプリはObjective-C か Swift というプログラミング言語で開発するらしい。

以前までObjective-C で作られてきたけど、ちょっと前にSwiftが発表されて段々Swiftに置き換わっている
→今からやるならSwiftでしょう。Apple様も推してるみたいですし。

調査の中で、「Swiftは新しい言語だからネットに技術記事が少ない。」といった記事が散見されましたが、自分たちのような初学者が手をつけるのに十分なくらいの情報はあるように感じました。

いざとなったらネットの諸先輩方が教えてくださる……よね??

フレームワークについてはなにそれ美味しいの状態なので、今後調査と開発を進めていく中で決めていきたいと思います。

開発のためにどんなツールが必要か

天下のGoogle先生に、おんぶにだっこです

  • Google Drive ・・・クラウド・ストレージ。ファイル共有ように使用。15GBまでなんと無料。最高。
  • Google Meet ・・・オンライン会議用。ブラウザで動く。画面共有できる。Googleアカウントあれば使える。最高。
  • Xcode ・・・iOSアプリのコーディング・ビルド・配布までこれでやるらしい。まだHello Worldしかしてない。全部英語……
  • LINE ・・・細々した連絡用。プロジェクト用に、別に別に用意したほうがいいのかな……

最低限これらを用いることにしました。

タスク管理とか、バージョン管理とかもツール使ってやっていったほうがいいみたいだけど、現状キャパオーバーなので随時取り入れていきたい

プロジェクトの運営について

週一でミーティング。
→進捗報告、学んだ内容の共有、次にやることの確認をメインに確認する会。

学習を主目的とし、すこしずつでも継続的に取り組む。

開発の情報をアウトプットしていく。(Qiita、Twitter)
プロジェクトメンバーのTwitter
たけだ
だしゅん

(ここまで書くのに半日くらいかかってる…… 続けられるんでしょうか…?)

運営方法についてはふわっとしか決めていないので、適宜更新していきたい。
そもそも運営の決め事ってこういうことなの感がありますが、今のところはこれで勘弁してきださい。

おわりに

全部が手探り状態でわちゃわちゃしていますが、とりあえず「開発投げ出さない」を念頭に取り組んでいきたいと思います。

良ろしければ、ご指導ご鞭撻のほどよろしくお願いします。

PS.最近麻雀の成績が悪すぎるので、アプリ公開までには人様に見せられるくらいまでもちなおしたいです。まる。

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

iOSアプリ開発:タイマーアプリ(10.アニメーションを作成する)

スクリーンショット 2020-10-28 11.35.01.png

記事

タイマーアプリを作成するためのポイントを複数記事に分けて掲載しています。
この記事では、カウントダウンタイマーを視覚的に楽しくするためのアニメーションの作成方法について掲載します。

環境

  • OS: macOS 10.15.7 (Catalina)
  • エディタ: Xcode 12.1
  • 言語: Swift
  • 主な使用ライブラリ: SwiftUI

Gitリポジトリ

以下のGitリポジトリのURLからサンプルコードをご覧いただけます。
https://github.com/msnsk/Qiita_Timer.git

手順

  1. どのようなアニメーションにするか考える
  2. アニメーションの View を作成する
  3. アニメーションさせる図形を用意する
  4. 図形の色を指定し、常に変化させる
  5. 図形を動かすアニメーションを適用する
  6. MainView にアニメーションの View を配置する

1. どのようなアニメーションにするか考える

現時点での MainView を見ると、TimerView / PickerView と ProgressBarView の間にやや隙間があるので、その空きスペースで図形をアニメーションさせて、視覚的に楽しくしようと思います。

具体的な動きとしては、小さめの円を二つ用意し、それを 12 時の方向にプログレスバー内側に接するような位置に配置し、数秒かけて、プログレスバーに沿ってぐるりと一周回る、というものにします。二つの円はそれぞれ時計回り、反時計回りに動きます。そして1周回るとまた 12 時の方向でぴったり重なります。

また2つの円の透明度を 0.5 にして、重なった時に色が混ざって透明度が 1 になるようにします。2つの円の色も、プログレスバーと同様に、常に変化させます。

2. アニメーションの View を作成する

AnimationView という名前で新規ファイルを作成します。Animation 構造体のプロパティには、TimeManager クラスのインスタンスを用意します。そのプロパティの値を常に参照するので、頭に @EnvironmentObject プロパティラッパーをつけます。

また、アニメーションで図形を配置する際に、スクリーンサイズを基準に位置を指定するので、事前にスクリーンサイズのプロパティを用意しておきます(ここでは幅のほうしか使わないですが、デバイスを横向きにした時にレイアウトを調整する場合は高さも必要です)。

AnimationView.swift
import SwiftUI

struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    var body: some View {

    }
}

3. アニメーションさせる図形を用意する

これから作成していくアニメーションは2つの円を動かします。

Circle() コンポーネントを body{} 内に2つ追加します。これらを ZStack{} でレイヤー上に重ねます。どちらが上でも構いません。

.frame() モディファイアで、サイズを 20 に指定します。かなり小さめの円です。

.offset() モディファイアは、配置位置を垂直方向に上へずらします。ここで、先に用意していたスクリーンの幅を格納するプロパティ screenWidth を基準に、垂直方向(y)に上へずらします。上にずらす場合は、負の値になります。反対に下へずらしたい時は正の値になります。ずらす長さはスクリーン幅 x 0.38 としました。これで画面中央より上、だいたいプログレスバーの少し内側に円が配置されます。

AnimationView.swift
struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)

            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
        }
    }
}

4. 図形の色を指定し、常に変化させる

次に、2つの円の色相を指定するプロパティを用意します。初期値はそれぞれ 0.5、0.3とします。

    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3

.foregroundColor モディファイアにて、上記色相プロパティの値を使用しつつ、hue(色相)、saturation(彩度)、brightness(明度)、opacity(透明度)を指定する形で、円に色をつけます。まず、引数 hue には、上記プロパティを入れます。そして、opacity はどちらの円も 0.5 にして半透明にするため、彩度、明度ともに最大値の 1 を指定しています。

//1つ目のCircleに対して
.foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))
//2つ目のCircleに対して
.foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))

そして、常に色を変化させるには、プロパティの costomHueA / B の値を常に変更し続ける必要があります。これは ProgressBarView 作成時にもやりましたが、 onReceive モディファイアで、TimeManager クラスの timer プロパティ(Timerクラスのpublishメソッド)をトリガーにすれば実現できます。

body{} 内の2つの Circle コンポーネントを格納している ZStack{} に対して onReceive モディファイアにを作成します。

そして、Timer.publish メソッドが 0.05 秒ごとに発動すると同時に、costomHueA / B の値も + 0.05 されるようにします。 色を作成する Color 構造体の引数 hue は 0 ~ 1 の Double の値しかとらないので、costomHueA / B がそれぞれ 1.0 になったら、0.0 に戻るように、if文で追加します。

.onReceive(timeManager.timer) { _ in
    self.costomHueA += 0.005
    if self.costomHueA >= 1.0 {
        self.costomHueA = 0.0
    }
    self.costomHueB += 0.005
    if self.costomHueB >= 1.0 {
        self.costomHueB = 0.0
    }
}

この時点で、コード全体は以下のようになっています。

AnimationView.swift
struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))

            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))
        }
        .onReceive(timeManager.timer) { _ in
            self.costomHueA += 0.005
            if self.costomHueA >= 1.0 {
                self.costomHueA = 0.0
            }
            self.costomHueB += 0.005
            if self.costomHueB >= 1.0 {
                self.costomHueB = 0.0
            }
        }
    }
}

5. 図形を動かすアニメーションを適用する

2つの円に、アニメーションに関わるモディファイアを追加していきます。

rotationEffect モディファイアで円を回転させます。この回転の角度によって、先に追加済みの offset モディファイアでずれる円の位置も、画面中央を軸に同じ角度だけ変わります。

よって、2つの円を円形プログレスバーに沿って移動させたい場合、rotationEffect の引数 degrees の () 内に、アニメーション開始時と終了時の2パターンの角度を指定し、一定間隔で、その2つを切り替えることによって、切り替え前と後の間の角度の値の変化が生じて、その変化がアニメーションで再現されます。結果的に2つの円が行ったり来たりするアニメーションになります。

ここでは、360°一周ぐるりと移動するアニメーションにしたいので、0°と360°を指定します。その角度の切り替えのトリガーとして、プロパティ clockwise を bool 型で用意します。初期値は true にしておきます。

@State var clockwise = true

プロパティ clockwise が true だったら円の回転は 0°、false だったら回転は360° となっています。一方、もう一つの Circle コンポーネントは逆にして、 clockwise が true だったら 360°、false だったら 0° にします。これにより、2つの円がお互いに逆向きに回転する動きになります。

//1つ目のCircleに対して
.rotationEffect(.degrees(clockwise ? 0 : 360))
//2つ目のCircleに対して
.rotationEffect(.degrees(clockwise ? 360 : 0))

rotationEffect モディファイアの下に animation モディファイアを追加します。これにより、animation モディファイアより上のモディファイアに対してアニメーションが適用されます。

アニメーションの種類はいくつかありますが、最初ゆっくり、真ん中速く、最後もゆっくり、という動きにしたいので、ここでは easeInOut を animation モディファイアの引数として適用します。そして、easeInOut の引数 duration には 5 を入れます。これは5秒かけて一回のアニメーションを実行するという意味です。

.animation(.easeInOut(duration: 5))

ただし、timer プロパティの発動間隔は毎0.05秒とかなり短いので、別のcount プロパティを Double 型で作成します。この AnimationView 構造体の中でだけ常に参照するので、頭に @State プロパティラッパーをつけています。

@State var count: Double = 0

手順4で作成済みの onReceive モディファイアの中に、まず count プロパティが 0 のときにclockwise の値が toggle で切り替わるようにします。すなわち、count が 0 のときにアニメーションが開始するようにします。

.onReceive(timeManager.timer) { _ in
    if self.count <= 0 {
        self.clockwise.toggle()
    }

    //(costomHue関連のコード省略)
}

さらに、時間経過とともに count プロパティの値を変化させるコードを記述します。

Timer.publish メソッドが 0.05 秒ごとに発動するのと一緒に、count プロパティの値も 0.05 秒ずつインクリメントさせます。そして、count プロパティの値が 5 になったら、count プロパティの値をまた 0 に戻すようにします。

.onReceive(timeManager.timer) { _ in
    if self.count <= 0 {
        self.clockwise.toggle()
    }
    if self.count < 5.00 {
        self.count += 0.05
    } else {
        self.count = 0
    }
    //(costomHue関連のコード省略)
}

これで 5 秒ごとに clockwise プロパティが toggle されて、アニメーションが発動します。アニメーション1回の所要時間も5秒にしているので、途切れることなく 5 秒毎にアニメーションが繰り返されるようになります。

今、コード全体は以下のようになっています。これで AnimationView の完成です。

AnimationView.swift
struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3
    @State var clockwise = true

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))
                .rotationEffect(.degrees(clockwise ? 0 : 360))
                .animation(.easeInOut(duration: 5))

            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))
                .rotationEffect(.degrees(clockwise ? 360 : 0))
                .animation(.easeInOut(duration: 5))
        }
        .onReceive(timeManager.timer) { _ in
            if self.count <= 0 {
                self.clockwise.toggle()
            }
            if self.count < 5.00 {
                self.count += 0.05
            } else {
                self.count = 0
            }

            self.costomHueA += 0.005
            if self.costomHueA >= 1.0 {
                self.costomHueA = 0.0
            }
            self.costomHueB += 0.005
            if self.costomHueB >= 1.0 {
                self.costomHueB = 0.0
            }
        }
    }
}

Canvas で AnimationView を確認します。下の gif 画像のようになっているはずです。
5p2wx-8k3l6.gif

6. MainView にアニメーションの View を配置する

それでは完成した AnimationView を MainView に配置していきます。

アニメーションの表示条件として、タイマーのステータスが .stopped 以外(.running または .pause)の時のみにします。

また、先に作成済みの SettingView の設定項目の中に Effect Animation のオン/オフのトグルスイッチがあります。ですので、このトグルスイッチに連動する TimeManager クラスの isEffectAnimationOn が true の時のみアニメーションが表示されるようにします。

上記2つを条件として if 文で記述します。

if timeManager.isEffectAnimationOn && timeManager.timerStatus != .stopped {
    AnimationView()
}

また、コード内の AnimationView の配置は、レイヤー上、 上プログレスバーより後ろにしたいので、ZStack{} の冒頭に記述します。

最終的に、MainView のコードは以下のようになります。

MainView
struct MainView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        ZStack {
            if timeManager.isEffectAnimationOn && timeManager.timerStatus != .stopped {
                AnimationView()
            }

            if timeManager.isProgressBarOn {
                ProgressBarView()
            }

            //(他のView省略)
        }
        .onReceive(timeManager.timer) { _ in
            //(省略)
        }
    }
}

Canvas で MainView を確認します。下の画像のようになります。
スクリーンショット 2020-10-28 11.44.42.png

さいごに

この「iOSアプリ開発:タイマーアプリ」シリーズは、ここまでの全10記事で完結となります。

アプリ内のボタンやテキスト、背景の色は全然指定していないので、色味に欠けるかもしれません。もしこのシリーズの記事をご参考にされる場合は、是非、そのあたりをご自身の手でカスタマイズしてみていただければと思います。

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

XcodeでThe file couldn’t be savedのビルドエラー

Xcodeビルドエラー "The file couldn’t be saved."ではまった件

ビルドエラーは以下:
/bin/sh -c /Users/xxxx/Library/Developer/Xcode/DerivedData/xxxxx-fmaccoypantpmwcbvalvgebzktwd/Build/Intermediates.noindex/xxxxx.build/Debug-iphonesimulator/xxxx.build/Script-2D6F48152518F1F300CCDBE0.sh

"The file couldn’t be saved.
Command PhaseScriptExecution failed with a nonzero exit code

この記事を参照:
https://github.com/Carthage/Carthage/issues/3056

ある方のコメントによると:

rm -rf ${TMPDIR}/TemporaryItems/carthage // 新しい追加する内容
/usr/local/bin/carthage copy-frameworks // 本来の内容

run scripts(Script-2D6F48152518F1F300CCDBE0.sh)へ追加すれば解決とのこと。

しかし、追加したけど、毎回新しく追加した内容が削除されてしまうと反映、解決できず。

${TMPDIR}/TemporaryItems このパスに入ってみると、
(A Document Being Saved By carthage)
(A Document Being Saved By carthage 1)
(A Document Being Saved By carthage 2)
...
このような名前のフォルダーがいっぱい!!これらをすべて削除したら、Clean Builder Folderして、
ブルドしたら、エラーが解消しました!

本来であれば、rm -rf ${TMPDIR}/TemporaryItems/carthageを追加したら、解消するはずだが、
なぜか追加しても消えるので余計な時間、2時間ぐらいもかかりました。

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

【Swift】クイズアプリの正解した時の表示方法【初心者】

はじめに

クイズアプリで正解した時の表示方法がわからなかったため、調べてまとめてみました。

実務未経験で、Swiftを独学で勉強しています。
学んだ事をアウトプットしていきたいと思います。
初学者のため、間違いがあるかも知れません。
その時は、教えていただけると幸いです。

環境

macOS Catalina10.15.4
Xcode11.7

完成図

sampleMove.gif

story boardで下記の画像のように画面を設定

sample1.png

UIImage、UIButtonとコードを接続する。

 @IBOutlet weak var answerBtn1: UIButton!
 @IBOutlet weak var answerBtn2: UIButton!
 @IBOutlet weak var answerBtn3: UIButton!
 @IBOutlet weak var answerBtn4: UIButton!

 @IBOutlet weak var maruImageView: UIImageView!

UIButtonは@IBActionでも接続する

 @IBAction func answerBtn1Action(_ sender: Any) {
    }


    @IBAction func answerBtn2Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く
    }


    @IBAction func answerBtn3Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く
    }

    @IBAction func answerBtn4Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く

    }

○画像を格納する(maru.png)

sample2.png

正解の時の処理

1、○画像を表示

コードはanswerBtn1Actionの中に書く

//○画像を表示する
maruImageView.image = UIImage(named: "maru.png")
//○画像の透過率を元に戻す。2回目以降ボタンを押す時、これを書かないと○画像が透明なままになる。
maruImageView.alpha = 1.0

2、正解の時、ボタンの色を青くする

answerBtn1.backgroundColor = .blue

3、1秒後に○の画像と、ボタンの色を消す

この時は、UIViewのアニメーションを使用。

//UIView.animateの機能を使い1秒後に色が戻る
 UIView.animate(withDuration: 1.0) {
      //ボタンの色をsystemOrengeに変更
      self.answerBtn1.backgroundColor = .systemOrange
      //○画像の透過率をゼロにする。ゼロで透明。
      self.maruImageView.alpha = .zero
}

コード全文

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var answerBtn1: UIButton!
    @IBOutlet weak var answerBtn2: UIButton!
    @IBOutlet weak var answerBtn3: UIButton!
    @IBOutlet weak var answerBtn4: UIButton!

    @IBOutlet weak var maruImageView: UIImageView!



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    //正解だった時の処理
    @IBAction func answerBtn1Action(_ sender: Any) {
        print("正解")
        answerBtn1.backgroundColor = .blue
        //○画像を表示
        maruImageView.image = UIImage(named: "maru.png")
        //○画像の透過率を元に戻す
        maruImageView.alpha = 1.0

        //UIView.animateの機能を使い1秒後に色が戻る
        UIView.animate(withDuration: 1.0) {
            //ボタンの色をsystemOrengeに変更
            self.answerBtn1.backgroundColor = .systemOrange
            //○画像の透過率をゼロにする。ゼロで透明。
            self.maruImageView.alpha = .zero
        }
    }


    @IBAction func answerBtn2Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く
    }


    @IBAction func answerBtn3Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く
    }

    @IBAction func answerBtn4Action(_ sender: Any) {
        //今回は使わないが本来はここに処理を書く

    }

}

参考サイト

https://qiita.com/hachinobu/items/57d4c305c907805b4a53

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

関数を理解しよう!

今回は、関数について学習したので、アウトプットしていきます
※以下の内容は、学習内容のアウトプット用のため、誤りがある場合があります。予めご了承ください

関数とは?

関数とは、あらかじめ複数の箇所に定義されている命令文を1つにまとめる機能です。

基本的な関数の宣言は以下の通りです。

qiita.rbvar
func <関数名>(){ 
     <>
 }

このように先頭に「func」と書きます。これは関数を意味する英語の「function」の略です。

次に簡単な例をみていきましょう!

qiita.rbvar
func kuku5dan(){ 
     for x in 1...9{
          print(5*x)
 }
 }

kuku5dan() //実行するためにこのように宣言する

実行結果
5
10
15
20
.
.

引数を使った関数宣言

●引数とは

引数とは、関数の実行時に関数に渡す値のことです。
関数はその引数を使用し、実行できます。

引数をしようした関数の宣言は以下の通りです。

qiita.rbvar
func <関数名>(<引数名><>){ 
     <>
 }

次に簡単な例をみていきましょう。

qiita.rbvar
func kuku(num:Int) { 
     for x in 1...9{
          print(num*x)
 }
 }
kuku(num:5) //5の段実行

●複数の引数

関数は、複数の引数を受け付けることができます。

qiita.rbvar
func <関数名>(<引数名1><型1>,<引数名2><型2>){ 
     <>
 }

上記のように「,」で簡単に区切ることができます。

こちらも簡単な例をみていきましょう。

qiita.rbvar
func rectangleArea(height:Int,width:Int){
 print(height*width)

}

ectangleArea(height: 3, width:4) //関数の呼び出し

上記の例は、長方形の面積を求める式を関数で宣言して、複数の引数を指定しています。

ラベルの指定

引数は、引数名の前にラベルを指定することができます。
ラベルを指定する理由は、なるべく自然な英語の文になるようにするためや、コードを書いていない人がパッと見て理解しやすいようにするためです。

基本的な構造を見ていきましょう。

qiita.rbvar
func <関数名>(<ラベル1><引数名1><型1>,<ラベル2><引数名2><型2>){ 
     <>
 }

このように、引数名の前に、ラベルを簡単に指定することができます。

関数の戻り値の定義

上記で解説してきた関数は関数内で処理が完結してきました。しかし、処理の内容によっては、関数が行った処理を使って、別の処理を実行したい場合があります。この時に利用するのが戻り値です。

関数に戻り値を定義する場合は、次のように関数名の後に「->」を書き、戻り値の型を指定します。また、実際に戻す値をreturnキーワードの後ろに指定します。

基本的な構造を見ていきましょう!

qiita.rbvar
func <関数名>() -> <戻り値の値の型>{ 
     <>
     return<戻り値>
 }

次に簡単な例を見ていきましょう。

qiita.rbvar
func rectangleArea(height:Int,width:Int) -> Int{
 let result = height*width
 return result //計算結果を戻す

}

var area = rectangleArea(height:5,width:6) //関数の実行結果が変数areaに代入されます
print(area)

最後に

最後に、今回を学習をした内容をまとめます。
・関数を使うと、重複したコードを1つにまとめることができる
・関数を使うには、関数の宣言と関数の呼び出しの2つの手順が必要
・引数を使うと、似た関数を1つのまとめることができる
・引数には複数の値を指定することができる
・ラベルを指定することで読みやすいコードになる
・関数の処理結果を、他のコードで利用したい場合は、戻り値を設定する

関数は、アプリ開発おいて非常に重要な役割をになっているので、しっかり理解を深めていきます。

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

【Core ML】自動生成されるMLモデルをアプリに組み込む

この記事はなに?

Create ML Appでトレーニングした独自のモデルを、アプリに導入するまでの手続きです。

環境

macOS 10.15.7
Xcode 12.1
Swift 5.3

手順

モデルをトレーニングする

この作業は、Create ML Appで行います。
トミカ(ミニカーの玩具)を識別するモデルを作成しました。

Xcodeプロジェクトに組み込む

Create ML Appから書き出した.mlmodel形式のモデルファイルは、ドラッグ&ドロップするだけでXcodeに組み込むことができます。
同時に、MLモデルのクラスを定義したコードが自動的に生成されます。

MLモデルのインスタンス

CoreMLフレームワーク発表当時のコードは一部、非推奨になっています。
現在は以下のコードで、インスタンスを作成できます。

モデルのインスタンスを作成する
let modelURL = Bundle.main.url(forResource: "MyTomicaClassifier", withExtension: "mlmodel")!        
let tomicaClassifier = try! VNCoreMLModel(for: MLModel(contentsOf: modelURL))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftのCodableの使い方 超個人的メモ

SwiftyJsonが便利だけど、Swift表標準機能であるCodableもそこそこ使いやすかったのでメモ

実践的ではないけど一番シンプルなCodableでjsonをinstanceに変換する例

structにCodableを継承させて、jsonをデータ変変換した後、JSONDecoder.decodeを使うだけ。
ただ、Codableで定義した型情報と、jsonの形が厳密に同じである必要がある。そのため、jsonのキーが一つでも欠けているとエラーになる。

var data = """
{
  "name": "Bob",
  "age": 20,
  "sex": "male",
}
""".data(using: .utf8)!

struct User: Codable {
  let name: String
  let age: Int
}

let users: User = try JSONDecoder().decode(User.self, from: data)
users // User(name: 1, age: 20)

実践的なCodableの使い方(jsonのキーが欠ける場合)

structを以下のようにclass変変更し、init関数内で初期化を行う。
純粋なswiftで書かれているので、分かりやすい。

var data = """
{
  "name": "Bob",
  "age": 20,
}
""".data(using: .utf8)!

class User: Codable {
  var name: String
  var age: Int
  var sex: String? // sexがjsonにない!

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? nil
        self.age = try container.decodeIfPresent(Int.self, forKey: .age) ?? nil
        self.sex = try container.decodeIfPresent(String.self, forKey: .sex) ?? nil
    }
}
let users: User = try JSONDecoder().decode(User.self, from: data)
users // User(name: "Bob", age: 20, sex: nil)

まとめ

SwiftyJsonと比べCodableもそんなに悪くない。

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

Xcode12でCarthageビルドがエラーになる件の回避策に関する情報

2020/10/26現在の情報です。

表題の件、公式の回避方法が公開されました。
Xcode12Workaround.md

  • Apple Silliconの登場によってarm64アーキテクチャーが実機とシミュレータで重複してしまうことが原因である模様
  • この回避策を行ったビルドでは(シミュレータ用のarm64アーキテクチャーを削除するため)Apple SilliconのMacでは使えないという制約がある模様
  • まもなく根本的な対策が行われる模様

どうやら根本的な対策が追って行われるようですが、新しいバージョンでは使い方とか設定方法が変わったりしないんですかね?
私は、今のうちにCocoaPodsに乗り換えるのも一つの選択肢かなと思います。

Firebaseみたいな有名どころのSDKもまだCarthageには正式対応していないですし、無理してCarthageを継続する意味はそんなにないような。。。
(※FirebaseのSwift Package Manager(SPM)対応もBetaなので、SPMは個人的にはちょっと時期尚早感があります…)

ちなみにこの問題の元々のissueはこちらです。
https://github.com/Carthage/Carthage/issues/3019

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

【Swift】入門書では教えてもらえなかったdismissをシンプルに記述する方法

入門書では教えてもらえなかった、よりシンプルにdismissを記述する方法を学んだので記載します。

入門書等でのdismiss(コード補完をそのまま利用した場合)

dismiss(animated: true, completion: nil)

よりシンプルなdismiss

dismiss(animated: true)

なぜ、completionを省略出来るのか?

・Apple 公式ドキュメントより
dismiss1.png
completion: (() -> void)? = nil)
の記載がある通り、completionに引数を渡さない場合は何も記述しなくてもnilが渡されるので、compolisionは省略することが出来ます。

で、completionって何?

・Apple 公式ドキュメントより
image.png
意訳すると、

completionは、
ViewControllerがdismiss(破棄)された後に、処理を実行する為のブロックで、何のreturnの値もパラメーターの値も持ちません。
多分、あなたはこの引数にnil入れるかもしれませんね。

とのことです。笑

completionは、完了達成という意味なので、
メソッドが完了した時に実行される処理のかたまり(ブロック)
と覚えるのが良さそう。

ちなみにいつ実行されるのか?

・Apple 公式ドキュメントより
image.png
viewDidDisappearが呼ばれた後にcompletionブロック内の処理が実行されるようです。



Appleの公式ドキュメント見るの少し楽しくなってきたので少しずつでも英語の勉強も兼ねて読んでいきたいと思います。


参考:Apple 公式ドキュメント(dismiss)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む