天気予報アプリをリリースしてみた
せっかくデベロッパーに登録しているので、そろそろアプリをリリースしようと思い立った。
今回は自分が実装で気をつけていることと、アプリの宣伝を兼ねて書きます。
経緯
数年前にiOS開発を始めた頃に作った「全国天気」というアプリの改良版にしようと考えた。 なぜそう考えたのかというと、単純に設計・実装力がこの数年でどれだけ伸びたのかなーというのを体感したかった。
iOSソフトウェアを開発するようになってから、Swift、Objective-Cはほぼ毎日取り組んだ。 MVCの概念すらまともに理解できずにSwiftをスクリプトのようなソースコードを書いてた初期の頃よりマシになったかなー。
概要
仕事では「汚い雑なコードを書いてとりあえず動いたからいい」ということも事情によってはやらないといけなかったりするが、今回は勉強のためなので、ガチに作った。実装する時に思い描いていることはこの数年でだいぶ変わってきた。主に以下を意識した。
もっといい書き方はないか
まずは結果を達成するための解を見つけてとりあえず書く。それができたら、簡潔な処理に書き直す。
無駄はないか
共通化できる処理はExtensionで書いたり、使いまわしたり。なんども同じ処理を書かない。
最善なパフォーマンスはどれなのか
APIから取得する値をどう処理するかによってパフォーマンスは変わってくる。保守する上でもやり方によっては機能追加が楽になる。
よくやってしまいがちなのは、Dictionaryにキー値をベタ書きにしてそのまま値を突っ込むやり方。これは実装は簡単だが、どこにどの値が入っているかわかりにくくなるため、保守が大変になる。
今回の処理の考え方としては、1インスタンスに複数の箱を用意しておき、その箱にものを詰めていくイメージ。1個の箱に必要な分を全て詰めたら次の箱をループを回して生成・詰める作業を繰り返す。全部詰めたら全ての箱をビューを保持するコントローラに渡す。
以下は処理を簡略化したもの。
var values: Array<[Any]> = [[]] //グローバル宣言 open func updateEntity(_ aValue: String) { values.append([“エリア名”]) let entity: WeatherEntity = WeatherEntity() entity.prefectureName = “都道府県名” entity.areaName = “エリア名” entity.updateDate = “日付” : : values.[area].append(entity) } (上記処理をループが完了するまで繰り返す)
データはキャッシュの概念を取り入れるため、APIから取得したデータはCoreDataに入れておく。参照時にすでに持っている場合はCoreDataから取り出し、なければAPIから取得する。
よくイメージするのは
ものを買うときにはお金が必要だが、財布にお金があれば財布から出し、なければ銀行へいきお金を下ろす。 財布にあたるのがユーザの端末、お金にあたるのがデータ、銀行はAPI、銀行へ向かうための交通費が通信費、という喩え。
スペルミスはないか
これは実装していてよく目にするのだが、スペルミスはなるべく起こらないように不明な単語は辞書を索く癖をつけている。日本語で考えて、それをプログラムに具現化する際に正しい英訳ができていないと、あとで見返した時に不整合に思えてくるため。ミスもおきやすくなる。類似処理のチェックのためにプロジェクト内検索を行うが、その際にちゃんと引っかかってくれた方が楽だし。
基本的なことだが、これらを意識できないとひどいものができあがる。
どのように振り返ったか
日記を日々つけていき、数年経った時に当時のものを見返せば、どのくらいスキルアップしたのかを定量的に測れると思います。
当時つけていた実装スキルの課題一覧をみてみたらひどすぎた(笑)
成果物
週間全国天気は以下ストアからダウンロードできます。
よろしければ使ってみてください。
公共電波が要らないチャットアプリをリリースしてみた
興味があったので勉強がてらにチャットアプリをAppleストアにリリースしてみた。
その際に勉強したことを書きます。
リリースしたアプリ
iOS App
BLE Messenger Lite by Ohkubo Yuhei
Mac App
BLEMes by Ohkubo Yuhei
このアプリで何ができる?
災害が発生した場合にWi-Fiなどの公共電波が使えない状態になることを想定し、端末から発信するBluetoothだけで通信ができるアプリ。Mac版とiOS版の相互互換があり、メッセージに関しては異なる種類のデバイスに送信できる。
作った理由
そういえば圏外のときってスマホ使えないんだっけ?と疑問に思いBluetoothにたどり着いた。あまり見かけない通信方法だったが、
「iOS×BLE Core Bluetoothプログラミング」
この本を読んで応用できるんではないかと思ったのがきっかけ。
このアプリを使う上でのメリットは
- ネットワークが用意されていない環境でも通信ができる
- 友達申請が不要。近くにいるアプリ起動中の端末なら誰でもチャットができる
- GATTが使えるので、ロジックの実装に幅が出る。プログラムでできることなら、実装次第で色々できてしまう
デメリットは
- Wi-Fi、4Gなどの利用に慣れているユーザにとっては大量データの送受信の通信速度がパフォーマンスが悪く、MB単位を超える通信はキツい
機能について
機能はLINEに似ているが、個人で作っている分圧倒的に少ない。
- メッセージ送受信にCoreBluetoothを使って通信を行う。bluetoothをON、かつアプリを起動しているユーザに対してメッセージ送受信を行う
- トークリストに送信可能なユーザには圏内表示をし、選んだユーザに対してトーク画面にてメッセージを送信する
- バックグラウンドでのメッセージ受信に対応しており、アプリがフォアグラウンドにいなくても通信が可能
- 受信時のプッシュ通知を表示する。または通知受信可否、バイブレーションのON/OFF切り替え機能
- LINEに似たUIで実装
- アプリ内課金にて背景色を変更できるアイテムを実装
- iOSアプリのみメッセージの他に画像、音声を送信可能* 非表示・ブロック機能を実装
開発環境について
このような開発環境で実装した。
言語について
開発言語については本職のObjective-Cにしようか迷ったが、現在進行形の言語であるSwiftにした。Swift2.3からと、思えばかなり前から実装してたんだな。Swift4.0メジャーアップデート後の対応はビルドエラーの海だったが調べながら進め、無事解決した。
詰まりどころ
送信バイト数に上限があるのはなんとなくわかっていたが、それにしても少なすぎる。もともとデータ通信用ではないしそれを無理やり使っているので仕方ないか。
単一で大きいファイルは送れないか、設計の段階で考えた。よくありがちな分割送信を思いつき実装したらうまくいった。
- 画像などを通信したい場合はデータを分割して送信する実装にする必要がある。主に画像データはバイナリデータに変換してあげれば送受信できる。実装する際は一度あたりの送信データ量が制約を超えていないか確認しておく
- 画像や長文テキストなどデータ量が上限を超える場合は、データを分割して送信し受信側で結合しデータを復元する。データは送信元で圧縮しそれを受け取った受信側で解凍する仕組み
ライブラリについて
ライブラリは一般的な最低限を利用している。
- libsqlite3.tbd : アドバタイズにて発生するユーザ、チャット送受信データを格納するため使用。ラッパーライブラリはFMDBを使用
- CoreBluetooth : このアプリでCoreBluetoothの通信を行う際に必要なライブラリ
- Toast : エラーメッセージをユーザに知らせるために使用
開発中に思ったこと
iOSはbluetoothをキャッシュするため解放する必要があるが、bluetoothのON/OFFをデバイス操作から行う。これを実装で解決する方法を模索したが見つからず、今後の課題となっている。
実際に使ってみての感想
実用性を図るため海外に行った時に試してみたが、simを用意していないときに非常に役に立った。
所感
チャットアプリを作るいい経験になった。