20201026のiOSに関する記事は9件です。

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

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

クロージャーとは?

クロージャー とは、再利用可能なひとまとまりの処理のことをいいます。
関数はクロージャーの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で続きを読む

【第一回】初心者二人で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で続きを読む

【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で続きを読む

OKI AE2100 & Node-REDでローコードIoTしてみた。その4実践編 2

Node-REDでローコードIoT実践編 2
MQTT Pub/Sub

はじめに

本記事はOKIの「AIエッジコンピューター」と呼ばれる AE2100 というゲートウェイ製品にNode-REDを載せて、ローコードIoTのプラットフォームにしようという記事の その4 Node-REDでローコードIoT実践編 2 MQTT Pub/Sub です。

その1 PythonでRS-485圧力センサーシミュレータ準備編
その2 DockerでローコードIoTプラットフォーム構築編
その3 Node-REDでローコードIoT実践編 1 ダッシュボード作成
その4 Node-REDでローコードIoT実践編 2 MQTT Pub/Sub (本記事)

前編では RS-485入力の圧力値をNode-RED でローカルに作ったダッシュボードにリアルタイム表示しました。
もうそこまでで十分なわけですが、いちおうIoT関連の記事なので、ネットワークを利用するところまでやらせてください!

こんなことやります

image.png

本編で行うのは最後の 4 MQTT Pub/Sub になります。
RS-485で受信した圧力値をクラウドに飛ばしてIoTらしいアプリに仕上げます。
使用するネットワークプロトコルはMQTTです。

MQTT

Node-RED 経験者なら、ほぼ間違いなくMQTTを使ったことがあるでしょうが、ここではMQTT初心者向けに少しだけ解説します。
MQTTとは、パブリッシュ/サブスクライブ型のメッセージキューです。
サーバーであるMQTTブローカーを仲介者として、複数のクライアントがサブスクライブ(購読)とパブリッシュ(発行)に分かれ、トピック名をキーワードとしてメッセージの送受信を行います。

image.png

1つのクライアントがパブリッシュとサブスクライブの両方を行うこともあります。
Node-RED ならば、MQTT、Node-RED 両方の初心者でも、設定だけで簡単に MQTT を試すことができます。

なおMQTTブローカーには、test.mosquitto.org を使わせていただきます。

Node-RED フロー作成

Node-RED のフローエディタ構成を再掲しました。
ワークスペース内のフローがこれから作成するフローです。
image.png

流量制限ノード

まず上図のフローの左下に追加した "1 data/10 sec" ノードですが、これは毎秒受信する圧力センサーのデータを10秒に1回に流量制限するものです。
無料で使わせていただくMQTTブローカーに毎秒データを送りつけるのは気が引けるので、遠慮して10秒に1回にします。

パレットにあるこの delay ノードを使用します。
image.png

これをワークスペースに置いて、ダブルクリックして以下のように設定して完了します。
image.png
このように流量の制限が設定だけで簡単にできてしまいます。

MQTTパブリッシュノード

次に、MQTTブローカーにセンサーデータをパブリッシュするノードを設定します。
パレットからこの mqtt out ノードを掴んで、ワークスペースにドロップします。
image.png

ダブルクリックして設定します。
まずは鉛筆アイコンをクリックして、MQTTブローカーの設定画面に移行します。下の右にある設定画面が開きます。
名前はとりあえず test.mosquitto.org としておきましょう。
サーバは今回は test.mosquitto.org と指定する必要があります。
ポートはデフォルトの1883でOKです。
クライアント名は、何でも良いのですが、ここでは AE2100 とします。
以上3つ設定したら、更新をクリックして初めの設定画面に戻ります。

トピック名はMQTTブローカー内でユニークである必要があります。
今回は ae2100/pressure とすればOKでしょう。
QoS1 にして、少なくとも1回はMQTTブローカーにデータが届くまで(複数回届く可能性があります)パブリッシュするようにします。

image.png

mqtt out の設定が完了したら、フローエディタの右上の デプロイ をクリックして保存・実行しましょう。
下図のように test.mosquitto.org ノードが 接続済 になったでしょうか?

image.png

ここでは 接続済 にならなくてもOKです。後ほど別の方法をご紹介します。
次の確認にすすみましょう。

フローの改造

RS485ノードと test.mosquitto.org ノードが接続済みになったので、1秒ごとにRS-485で入力される圧力データが10秒ごとにMQTTブローカーに送信されているはずです。

MQTTサブスクライブしてそのデータを受信してみましょう。
一度、MQTTブローカーにサブスクライブしておくと、以降パブリッシュがある度に、MQTTブローカーがパブリッシュされたデータを転送してくれます。

image.png

本来、サブスクライブは別クライアントで行うべきでしょうが、今回は Node-RED での説明を兼ねて、今まで使ってきたフローを2つに分けて、上の図のMQTTクライアント 1と2を Node-RED の1つのワークスペース上に実装します。

image.png

上のフローはセンサーデータを収集してクラウドにアップロードするエッジゲートウェイを想定しています。

RS485ノードからの圧力データはそのままダッシュボードに表示せず、MQTTブローカーにパブリッシュするだけにします。

そして下のフローは、エッジからのデータを受信してダッシュボード表示するWebアプリケーションを想定しています。
MQTTブローカーから転送された圧力データを受信してダッシュボードに表示します。

作業内容としては mqtt in ノードを新規に追加して、gaugechart ノードをこちらにつなぎ替えるだけです。

ダッシュボードのプロットが10秒に1回になれば、MQTTサブスクライブが確認できるはずです。

MQTTサブスクライブノード

それではmqtt in ノードを追加・設定しましょう。
パレットから下図のノードをワークスペースにおいて、ダブルクリックです。
image.png

サーバにはすでに test.mosquitto.org:1883 と入っているはずです。
(違う場合、ドロップダウンメニューで選択してください。)
トピック名にはパブリッシュ側の mqtt out ノードに設定した ae2100/pressure を入力します。
出力はデフォルトの自動判定のままにして、文字列として受信するようにします。
名前test.mosquitto.org とでもしておきましょう。

image.png

最後に、RS485ノードに接続している gaugechart のワイヤーを削除して、以下のように今追加した mqtt in ノードの右に置き、接続し直します。

image.png

以上で設定は終わりです。デプロイ をクリックして、保存・実行してみてください。
ダッシュボードに10秒に1回、圧力値がプロットされるはずです!

image.png

test.mosquitto.org に接続できない!

実はこの無料サーバーは時々つながらない事があります。
このサーバーはMQTTブローカーのリファレンス実装を公開している mosquitto.org により運用されているのですが、我々MQTTクライアント側がテストのために使用する目的だけでなく、MQTTブローカー自体をテストする目的でも使われており、不安定になったり、ダウンすることがあるそうです。

運悪くちょうどダウンしている場合、2,3日待ってトライしてみてください。
いや、今すぐ試してみたい!場合、このサービスはいかがでしょうか。
毎日パスワードを変更する必要がありますが、登録なしに無料で使えます。
もしくは node-red-contrib-mqtt-broker ライブラリを追加して、Node-RED上でMQTTブローカーを立ち上げる方法もあります。

さいごに

AE2100 によるローコードIoT開発、いかがだったでしょうか。
今回のサンプルアプリはローコードどころか、ノーコードでできてしまいました。

インタラクティブにアクセスする手段がSSHクライアントかXサーバー経由くらいしかないAE2100の使い方として、他のマシンでコンテナ内にアプリを作って、AE2100にそれをデプロイして実行するのが通常だと思います。

しかしNode-REDが動くと、AE2100で直接開発しても全く苦にならず、特に今回のシリアル通信のようなAE2100のハードウェアを使う場合、AE2100で直接開発することになるので、Node-RED は大きな助けになるはずです。

確かにNode-REDはメモリ食いだし、処理速度も速いとは言えないのですが、1秒くらいのレスポンスなら十分ではないでしょうか。
(まずNode-REDでぱぱっと作ってみて、処理速度が足りなさそうだったら、Node.jsやC言語で作り直す、というやり方もあるでしょう。)

これで4編にわたる記事もようやく終わりになります。
こんなに長くなるとは思わなかったのですが、AE2100 のユーザーのみなさんに少しでもお役に立てば幸いです。
最後の最後にお約束ですが、本記事に関してOKIは何も関知しないので、記事の内容に関してOKIに問い合わせることがないようにお願いいたします。

  • このエントリーをはてなブックマークに追加
  • 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で続きを読む

ShortcutsによるiOSのSafari向けブラウザ拡張機能作成

概要

iOSでもBookmarkletによってSafariで閲覧中のページのDOMなどにアクセス可能なことはよく知られていますが、Shortcutsでも似たようなことが可能ですので、Bookmarkketと比較した場合のメリット・デメリットと併せて、簡単なサンプルを紹介します。

Bookmarkletとの比較

メリット

  • 外部アプリとの連携が可能
    • JavaScriptの実行だけに留まらず、Shortcutsに対応している様々なアプリケーションとの連携が可能です
  • 配布が容易
    • 共有リンクなどを利用して、作成したShortcutを他のユーザに配布することが出来ます
  • Safariの共有メニューから実行可能
    • Bookmarkの一覧からではなく、一般的なアプリと同様に共有メニューから選択して実行することが出来ます
  • Safariだけでなく、TwitterやDiscordなどの内蔵ブラウザ(WebView?)からでも実行可能

デメリット

  • Shortcutsアプリのインストールが必要
  • 閲覧中のページ内JSで定義された変数へアクセスできない? (DOMへのアクセスは可能ですが、ページ内のJSとは別のスコープで実行されているのかも知れません)

※ 適宜追記します

準備

  • Shortcutsアプリをインストールしていない場合はAppStoreからインストールする。
  • 自身が作成したShortcut以外を実行する場合は、信用されていないShortcutの実行を事前に許可する

IMG_0738.PNGIMG_0739.PNG

実践

Safariで閲覧中のWebページのタイトルとURLをTwitterへ投稿するShortcutを作成してみます。

  1. Shortcutsアプリを開き右上の「+」をタップ

image.png
2. 右上の「…」をタップ


3. 「Show in Share Sheet」をタップし、ブラウザの共有メニューから実行可能にする


4. 「Share Sheet Type」から「Safari web pages」のみを選択して、右上の「Done」をタップ


5. [+ Add Action]をタップし、「Run JavaScript on Web Page」を選択


6. 「Web Page」をタップし、「Shortcut Input」を選択


7. 実行するJavaScriptの内容を編集

let result = {};
result.title = document.title;
result.href = document.location.href;
completion(result);
  1. 「+」をタップして「Twitter」を選択


9. 「Tweet」を選択


10.ツイート時の本文を編集して「Next」をタップ

  1. 作成したShortcutのタイトルを設定して「Done」をタップ


12. My Shortcutsの一覧に保存されたことを確認する


13. Safariで任意のページを開き、共有ボタンをタップし、作成したShortcutを選択

  1. 初回実行時にページへのアクセス許可を求められるので許可する

  1. 閲覧中ページのタイトルとURLが入力された状態のツイート画面に遷移する

まとめ

  • ShortcutsアプリからでもBookmarkletの様に、閲覧中のWebページに対してJavaScriptの実行が可能
  • 外部のアプリケーションと連携したブラウザ拡張機能を、iOS端末単体で作成可能
  • このエントリーをはてなブックマークに追加
  • 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: "mlmodelc")!        
let tomicaClassifier = try! VNCoreMLModel(for: MLModel(contentsOf: modelURL))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS/Androidアプリのセキュリティ関連の参考リンク

ちょっとしたきっかけがあって、iOS/Androidアプリのセキュリティに関して情報を収集する必要がありました。

せっかくなので私が出会った良記事をシェアしたいと思います。

OWASP Mobile Top 10

  • OWASPは「Open Web Application Security Project」の略で、「オワスプ」と読むようです。
  • ソフトウェアのセキュリティ環境や、セキュリティを高めるための技術を共有・普及することを目的として活動しているボランティア組織だそうです。
  • WebアプリのOWASP Top 10が有名ですが、OWASP Mobile Top 10はそのモバイルアプリ版です。
  • ソフトウェアを開発する上で、セキュリティとして警戒をしなければいけない項目のTOP10をレポートしています。
  • 何しろ有名どころなので、まずはこれを押さえる必要があると思います。顧客や上席に対する説明ではOWASPのレポートを参考文献に記載にすると説得力が増しそうです(笑)

OWASP Mobile Top 10 - 2016 日本語訳

  • OWASP Mobile Top 10の最新版レポートは2016年なのですが(ちょっと前なのですね)、有志によるその日本語訳です。

【セキュリティ】OWASP準拠の脆弱でない iOS/Androidアプリ開発を行うためのポイントを解説

  • OWASP Mobile Top10カテゴリに準拠しつつ iOS/Androidアプリ開発を行うためのポイントを解説してくれている、実践的な記事です。

iOS/Android セキュリティガイドライン

  • 実務/実装に即した内容になっている素晴らしい記事です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む