Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

Swift初心者ですがiPhoneアプリ「ポケット糖質量」をリリースいたしました

こんにちは。さくらです。
Rails版・Android版に続き、iOS版のアプリ「ポケット糖質量」をリリースいたしました。

ポケット糖質量

ポケット糖質量

  • Yukari Sakurai
  • ヘルスケア/フィットネス
  • 無料

食品に含まれる糖質量を便利に表示・検索出来るシンプルなアプリです。
もしよろしければダウンロードしてみてくださいね(●´ω`●)

f:id:sakura_bird1:20180417171423p:plain

Android版リリースの時の記事はこちらです。
sakura-bird1.hatenablog.com
Web版リリースの時の記事はこちらです。
sakura-bird1.hatenablog.com

自分がiOS版アプリを使いたいという理由もありましたが、
SwiftやiOS開発にとても興味があったので、今回実際にコードを組み立てて
アプリリリースまで持っていくことが出来て本当に嬉しいです。

最初にSwiftをいじったのはこの記事の頃ですね。
sakura-bird1.hatenablog.com

ここから休み休みですが、サンプルを書き溜めて実際にアプリに着手したのは
3月になっていました。

実はこのアプリはGithubソースコードを公開しています。
経験者の方からしたらひどいコードだと思いますが…。
github.com

最初のcommitが3/21で4/13にcommitした分をリリースしましたので、
1ヶ月弱ぐらいでしょうか。
この期間はなるべく毎日時間を取るようにして頑張っていました。

Android版を作った時は、数年Androidに関わっているのにあらゆる点で力不足を
感じていて(しかもここのところ記憶力がめっちゃ低下中)、
情けなくて、後ろ向きな気持ちでいっぱいでした。

でもiPhone版を作っている時は、プログラミングを始めた頃の「動いて嬉しい!」
という素朴な喜びをたくさん感じられて、幸せな時間を過ごせたと思います。


f:id:sakura_bird1:20180417211034p:plain

Swiftという言語も気に入っています。
Swiftのコードは読みやすいし、
自分のような初心者にも書きやすいように思います。
でも勉強が全然足りていなくて雰囲気で書いてしまった部分が多いので、
もっと言語仕様を押さえて使いこなしたいです。

Swiftはバージョンアップで仕様が変わりますよね。
この先もちゃんと付いていけるかな。ちょい心配。


f:id:sakura_bird1:20180418040802p:plain:w300

SDKのターゲットはiOS11以上にしました。
とにかくリリースしたかったので、複雑さを無くして
出来る限り開発のハードルを下げました。
そもそもポケット糖質量はほとんど静的データを取り扱っており、
非常に簡単な部類のアプリです。
それを更にAndroid版にはある機能を減らしたり、
サポートSDKを11以上にしたりで簡単になるようにしました。
例えば検索画面は、Android版は検索窓に入力した文字が
次回からサジェストされますが、iOS版はそれはありません。
iOS11以上で使えるSearchControllerを使って楽に実装するようにしました。
他にもアプリのビルドも本番用とデバッグ用でBundle IDを分けたりしていません。
(これは今後やるつもりですが)ビルド周りは特に手を抜いてる気がします。

f:id:sakura_bird1:20180418041228p:plain:w250

どうやってiOSの勉強をしたのかは次のような感じです。
Appleの公式チュートリアルを2つやった
 1. 「A Swift Tour
 2. 「FoodTracker
YouTubeチュートリアル動画を色々見た
 英語になっちゃいますが、「Swift autolayout」のように検索すると色々出てきます。
 本当に参考になりましたし、Xcodeの使い方もだいぶわかりました。
 お金のある方は日本語の動画のあるスクールを受講するといいんでしょうね。
 私が心のなかで師匠と呼んでいるのはブライアンさんというお方です。おすすめ!
www.youtube.com

以上の知識を核としてWeb記事で補完し、
たまに人のコードをチラ見して勉強しました。

本を1冊も読んでいないんですが、Swiftの言語仕様を
網羅している解説本を読みたいです。
適当に書いてる部分が多いのを自覚してます。

開発で苦労したところは、レイアウトや画面遷移まわりです。
メインのTableViewを別のControllerに埋め込んで使い回す部分や
AutoLayoutの思い通りにいかなさなどです。こんな記事も書いていました。
sakura-bird1.hatenablog.com

それでも素晴らしいOSSや技術記事に本当に助けていただきました。
別途記事にしたいと思っています。
情報を発信してくださっている方々、本当に本当にありがとうございました!


そしてとうとう私も税込み¥12,744払ってApple Developerになってしまいました。
f:id:sakura_bird1:20180417211833p:plain

1年で有効期限切れるし、Androidと違って高いですね(TдT)
ポケット糖質量は収益を期待していませんが、Apple税ぐらいは
稼いでもらいたいものです。
次回のアプリを作る時も、Apple税がもったいないのでiOSファーストに
なりそうです。

一匹の蟻も通さないような恐ろしいイメージのあった
AppStoreの審査ですが、以外にも一発で通過しました。
これには拍子抜けでしたが良かったです。
公式サイトやプライバシーポリシーのページを設定したのもよかったんでしょうか?
だとすると、Web版ポケット糖質量を閉鎖しない方がいいかもしれませんね。
リリース後放置状態なので、閉鎖も考えていたのですが保留にしておきます。


f:id:sakura_bird1:20180418142803p:plain:w250

今後ですが、作ったアプリの改修作業を頑張ります。
Androidアプリの「インコ発信確認」のメンテナンスと
音声追加、ドライブモード(Bluetooth)追加をしたいと思っています。
sakura-bird1.hatenablog.com


あと、またミニアプリを作りたいと思っています。

それでは読んでくれてありがとうございました!


※いらすとやさんの画像お借りしてます。
毎度感謝しております( ´∀`)





Macで rails serverでhttp://localhost:3000を開始したがctrl+c でサーバーが停止しなくなってしまった時のコマンド

$ rails server

Macで上記のコマンドでrailsのローカルサーバー(WEBrickの通常のポート3000を使用しています)
を開始しましたが、ctrl+c でサーバーが停止しなくなってしまいました。
私はctrl+zを押したような気がしますのでそれが原因だと思います。

このようなメッセージが表示されました。

A server is already running. Check /Users/sakura/Documents/Railsアプリのある場所/tmp/pids/server.pid.
Exiting

次のコマンドで3000番のポートで実行中のプロセスを終了できます。

$ kill -9 $(lsof -i tcp:3000 -t)

以上です。

お名前.comで取得した独自ドメインをHerokuでSSL対応しました

こんにちは。さくらです。
Web版ポケット糖質量(Railsで作っています。)をhttpのまま放置していたのですが、
やっとhttps対応しました。
https://www.pockettoushituryou.com/

このエントリーは覚書です。

前提

  • お名前.comでドメイン取得が済んでいる
  • Herokuに有料のリポジトリを持っている(私のは月7$のHobbyプランです)

Heroku側の設定

Automated Certificate Management(ACM)という機能を使います。
Automated Certificate Management | Heroku Dev Center

Herokuで独自ドメインに無料で、しかも自動でSSL対応出来る素敵な機能です。

ACMを有効化します。

$ heroku certs:auto:enable

ACMが有効になっているか確認します。

$ heroku certs:auto

私は失敗していました。後述するお名前.com側でのDNS設定をしていなかったからです。
f:id:sakura_bird1:20180317022347p:plain:w300

Heroku からACM設定が失敗したよ、というメールも届きました。

TroubleshootingにDNSターゲットを「 {your-domain}.herokudns.com」という形式で指していなければならないとあります。
https://devcenter.heroku.com/articles/automated-certificate-management#troubleshooting

この設定をお名前.com側で行います。

お名前.com側の設定

お名前.comにログインします。
ドメイン取るならお名前.com|ドメイン取得 最安値 1円!

ドメイン > ドメイン詳細 > ネームサーバー設定
の画面右上の「ドメイン設定」ボタンをクリックします。

f:id:sakura_bird1:20180317013412p:plain:w300

DNS関連機能の設定をクリックします。

ドメイン一覧からドメインを選択して「次へ進む」ボタンをクリックします。
このような画面が表示されます。

f:id:sakura_bird1:20180317013814p:plain:w300

DNSレコード設定を利用する の右の「設定する」ボタンをクリックします。

DNSレコード設定画面が表示されます。
「A/AAAA/CNAME/MX/NS/TXT/SRV/DSレコード」という欄に設定していきます。

f:id:sakura_bird1:20180317014059p:plain:w300

example.comというドメインを設定する場合

項目 設定値
ホスト名 www
TYPE CNAME
TTL 3600(デフォルト)
VALUE www.example.com.herokudns.com
優先 -
状態 有効

入力したら「追加」ボタンを押します。

f:id:sakura_bird1:20180317015730p:plain

「確認画面へ進む」ボタンを押します。

確認画面が表示されるので、よければ「設定する」ボタンを押します。

[お名前.com]DNSレコード設定 完了通知というメールが届きます。

これで設定完了です。


しばらくしてからHeroku側を更新します。

$ heroku certs:auto:refresh

f:id:sakura_bird1:20180317023531p:plain

状態を確認します。

$ heroku certs:auto

1つしかDNS設定していないので1つ失敗したままですが、StatusがOKになりました。
f:id:sakura_bird1:20180317024037p:plain:w300

私がやった時は変更から10分〜13分ぐらいでHeroku側のSSL対応も完了しました。

対応は以上です。

参考サイト様

Herokuアプリにお名前comで取得したドメインを設定 - americandog1993の日記
ありがとうございました(*‘ω‘ *)

その他

ただ、せっかくSSL対応しましたが、Web版ポケット糖質量は閉鎖するかもしれません。
どうしても手が回らずに放置状態になってしまっているし、ユーザー様はほぼスマホアプリのユーザー様です。
スマホアプリ用にデータ自動更新用のAPIがあるのですが、
当初思っていたよりデータ入力をすることが出来なくてAPIいらないや!となってしまいました。
ついにアプリからAPIにアクセスしないように修正してしまいました。
サーバーサイドの知識も昨年の春から止まっているんですよね。
悔しいからサーバーを借り続けているみたいなもったいない状態です。
本当に思ったようにいかないですね(´;ω;`)

UITableView + Static Cellsでアプリ内設定画面を作成するサンプル(XCode9, Swift4, StoryBoard使用)

アプリ内の設定画面のサンプルを作りました。
ステップ・バイ・ステップで作成方法を書いていきます。

※ 当初、記事を書いていたらチュートリアルっぽくなってきたので
チュートリアルとタイトルに付けていたのですが、
記事公開直後に私は特に設定画面のスタンダードに詳しくないから自信がない
と思ってしまったということと、
アプリのバージョンをSettings.bundleあたりでなくアプリ内の設定画面で表示するのは
イマイチな例だったかもしれないなーと思いつつあるんだけど
書いてしまったしな〜〜〜という状況になってしまったので、タイトルはサンプルにしました。
申し訳ありませんが、こんな例があるんだなーぐらいに受け止めていただければ幸いです。
グダグダとすみません(´-﹏-`;)

開発環境

環境はXcode9.2、Swift4.0を使用しています。

サンプルの仕様

このようなシンプルなものを作ります。

f:id:sakura_bird1:20180307211415p:plain:w200

  • 「名前」はクリックすると入力画面に遷移し、入力された値をUserDefaultsクラスを使ってアプリ内に保存します。
  • 「アプリバージョン」はアプリ内でバージョンを取得して表示します。
  • 「ライセンス」はUITableViewのセクション内の行数を2行にするためのダミーです。

サンプルの実装

新しくプロジェクトを作成します。
テンプレート選択の箇所は、iOS「Single View App」を選択します。

不要なクラスなどの削除

デフォルトで作成される「ViewController.swift」を右クリック > Deleteを選択して削除します。

f:id:sakura_bird1:20180307214707p:plain:w200


Main.storyboardを開いてデフォルトで作成された「View Controller Scene」をクリック > deleteキーで削除します。

f:id:sakura_bird1:20180307215019p:plain:w200

設定画面を設置する

Main.storyboardにObject Libraryから「Table View Controller」を設置します。
右側のAttributes Inspectorの中の「Is Initial View Controller」にチェックしておきます。

f:id:sakura_bird1:20180307215808p:plain:w200


対応するクラスのファイルを作成します。
File > New > File… > Cocoa Touch Classを選択してNextボタンを押します。

次のダイアログで、Classを「SettingsTableViewController」、Subclass ofを「UITableViewController」にします。
Nextボタン > Createボタンを押し、作成します。

f:id:sakura_bird1:20180307220946p:plain:w200


Main.storyboardを開き、左側のDocument Outlineから「Table View Controller」を選択します。
右側のIdentity InspectorのCustom ClassのClassを「SettingsTableViewController」にします。

f:id:sakura_bird1:20180307222555p:plain:w200


左側のDocument Outlineから「Table View Controller」を選択して
Xcodeのメニュー > Editor > Embed In > Navigation Controller を選択します。

f:id:sakura_bird1:20180307222048p:plain:w200

Table View sectionを設定する

左側のDocument Outlineから「Table View」を選択します。
右側のAttributes Inspectorの項目を次のように変えます。

Content Static Cells
Sections 2
Style Grouped

f:id:sakura_bird1:20180307223934p:plain:w300


左側のDocument OutlineからTable Viewの下の「Section-1」を選択します。
右側のAttributes InspectorのTable View Sectionの項目を次のように変更します。

Rows 1
Header 設定

同様に、「Section-2」を次のように変更します。

Rows 2
Header その他

f:id:sakura_bird1:20180307225408p:plain:w200

Table View cellを設定する

左側のDocument Outlineから1つめの「Table View Cell」を選択します。
右側のAttributes InspectorのTable View Cellの項目を次のように変えます。

Style Right Detail

f:id:sakura_bird1:20180307230757p:plain:w200

セルの内側のContent View の内側にある「Title」を選択して
Attributes InspectorのLabelのTextを「Title」→「名前」に変更します。

f:id:sakura_bird1:20180307231645p:plain:w200

同様に「Detail」のTextを削除し、Colorはライトグレーを選択します。

f:id:sakura_bird1:20180307232236p:plain:w200


同じように「その他」セクションを設定します。

f:id:sakura_bird1:20180307234218p:plain:w300

セルの項目をソースコードに接続する

UITableViewでもStatic Cellsで作ったものは、通常の画面のように
直接セルの中のフィールドからソースコードにドラッグ&ドロップして
IBOutletの定義が出来ます。

Assistant Editorをクリックしてソースコードを開きます。
先程作成した「SettingsTableViewController」となっているのを確認してください。

f:id:sakura_bird1:20180308003151p:plain:w200


名前のDetailをDocument Outlineから選択し、
コントロールキーを押しながらソースコードにドラッグします。
classの下あたりでドロップすると、ダイアログが表示されます。

f:id:sakura_bird1:20180308023932p:plain:w300

Nameに「nameLabel」と入力してConnectを押します。

f:id:sakura_bird1:20180308024025p:plain:w200

コードが挿入されます。

同様にアプリバージョンのDetailも「versionLabel」と入力してConnectします。

  @IBOutlet weak var nameLabel: UILabel!
  @IBOutlet weak var versionLabel: UILabel!

ソースコードの編集

セクションとセルの数を設定

Standard EditorでSettingsTableViewControllerを開きます。
まず次の2つの関数を変更します。その下にコメント行がたくさんありますが削除してしまって大丈夫です。

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 0
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 0
    }

次のように修正します。

    // MARK: - Table view data source

  override func numberOfSections(in tableView: UITableView) -> Int {
    // セクションの数を返します
    return 2
  }

  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // それぞれのセクション毎に何行のセルがあるかを返します
    switch section {
    case 0: // 「設定」のセクション
      return 1
    case 1: // 「その他」のセクション
      return 2
    default: // ここが実行されることはないはず
      return 0
    }
  }

このようにセクションとセルの数を書かなければいけないところが手間ですね。

ここで画面左上のBuild and Runボタン(▶)を押して、一度実行してみます。
セルの右側には何も表示されませんが、ちゃんと表示されました。

f:id:sakura_bird1:20180308021842p:plain:w200

アプリバージョンの表示

アプリバージョンを表示します。
viewDidLoad関数を次のように変更します。

  override func viewDidLoad() {
    super.viewDidLoad()

    // アプリのバージョン
    if let version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String {
      versionLabel.text = version
    }
  }

▶ボタンを押して実行してみます。
セルの右側にバージョンが表示されました。
バージョンにつきましては「CFBundleShortVersionString」で調べてみて下さい。

f:id:sakura_bird1:20180308024647p:plain:w200

名前の表示

UserDefaultsの情報を画面にセットする

先程の関数のsuper.viewDidLoad()の下に次の行を書き加えて下さい。

    // UserDefaultsの情報を画面にセットする
    if let name = UserDefaults.standard.value(forKey: "name") as? String {
      nameLabel.text = name
    }

アプリ内の保存領域から「name」というキーとセットになっている文字があれば画面にセットしています。
アプリ内の保存領域については「UserDefaults」で調べてみて下さい。

ただ、今は実行しても何も表示されません。
nameというキーで値を保存したことがないからです。

次に名前の入力画面を作成して保存、遷移元の画面も更新する処理を書いていきます。

名前の入力画面を作成

Main.storyboardを開いてObject Libraryから「Table View Controller」を設置します。

f:id:sakura_bird1:20180308030634p:plain:w200



対応するクラスのファイルを作成します。
File > New > File… > Cocoa Touch Classを選択してNextボタンを押します。

次のダイアログで、Classを「SettingsNameTableViewController」、Subclass ofを「UITableViewController」にします。
Nextボタン > Createボタンを押し、作成します。

Main.storyboardを開き、左側のDocument Outlineから「Table View Controller」を選択します。
右側のIdentity InspectorのCustom ClassのClassをクリックして
「SettingsNameTableViewController」を選択します。

f:id:sakura_bird1:20180308031455p:plain:w300

名前の入力画面へのセグエを追加

左側のDocument Outlineから
「Settings Table View Controller Scene」を選択し、「Table View」の下の
「設定」の下の「Table View Cell」を選択します。

そこから先程設置した画面の「Table View」までコントロールキーを押しながら
ドラッグします。

セグエの種類を選択するポップアップが表示されます。
「Show」を選択して下さい。

f:id:sakura_bird1:20180308033533p:plain:w300

ここで▶ボタンを押して実行してみます。
名前のセルをクリックすると、次の画面が表示されます。
まだ何もない行が表示されるだけです。

名前の入力画面の設定

では、入力欄を定義していきます。
設定画面で行ったのと同じように、
左側のDocument Outlineから「Table View」を選択します。
右側のAttributes Inspectorの項目を次のように変えます。

Content Static Cells
Sections 1
Style Grouped

f:id:sakura_bird1:20180308034352p:plain:w300

セクションも編集します。

左側のDocument OutlineからTable Viewの下の「Table View Section」を選択します。
右側のAttributes InspectorのTable View Sectionの項目を次のように変更します。

Rows 1
Header 名前の編集

f:id:sakura_bird1:20180308165340p:plain:w300


左側のDocument Outlineから「Content View」を選択します。
Object Libraryから「Text Field」を選択し、ドラッグ・アンド・ドロップで
Content View内に設置します。

f:id:sakura_bird1:20180308170234p:plain:w300


設置したText Fieldを選択し、Constraintsを加えていきます。
次の画像のように、上下左右に16と入力してAdd Constraintsをクリックします。

f:id:sakura_bird1:20180308172328p:plain:w250


入力欄の属性を4点変更します。
Attribute Inspectorを開いて次のように編集しましょう。

  • Placeholderに「名前を入力してください」と入力します。
  • デフォルトだと、入力欄の周りに囲み枠が付いているのでBorder Styleを一番左にして非表示にします。
  • Clear Buttonを「Is Always visible」にします。
  • 「Text Input Traits」の中の「Return Key」を「Done」にします。

f:id:sakura_bird1:20180308220624p:plain:w150

セルの項目をソースコードに接続する

設定画面と同様にAssistant Editorをクリックしてソースコードを開きます。
先程作成した「SettingsNameTableViewController」となっているのを確認してください。

名前のText FieldをDocument Outlineから選択し、
コントロールキーを押しながらソースコードにドラッグします。
classの下あたりでドロップすると、ダイアログが表示されます。

Nameに「nameTextField」と入力してConnectを押します。

f:id:sakura_bird1:20180308213848p:plain:w300

コードが挿入されます。

  @IBOutlet weak var nameTextField: UITextField!

ここで実行してみますと、まだ名前の入力画面には何も表示されません。
ソースコードを編集しセクションとセルの数を記述することで表示されます。

セクションとセルの数を設定

Standard EditorでSettingsNameTableViewControllerを開きます。
設定画面と同じように修正します。この関数の後ろのコメント行も削除して大丈夫です。

    // MARK: - Table view data source

  override func numberOfSections(in tableView: UITableView) -> Int {
    // セクションの数を返します
    return 1
  }

  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // それぞれのセクション毎に何行のセルがあるかを返します
    return 1
  }

シンプルなサンプルなのでたった1つしかセクションとセルがありません。
▶ボタンを押して実行してみると入力欄が表示されるようになりました。
入力欄をクリックすると入力も出来ます。
まだ入力されたものをプログラム内で受取り保存する仕組みがないので、
前の画面に戻ったら消えてしまいます。

f:id:sakura_bird1:20180308215314p:plain:w200

UITextFieldDelegateの実装

SettingsTableViewControllerクラスにUITextFieldDelegateプロトコルを実装します。
UITableViewControllerの後ろにUITextFieldDelegateを追加してください。

class SettingsTableViewController: UITableViewController, UITextFieldDelegate {

次にviewDidLoadの「super.viewDidLoad()」の後に次のコードを追加してください。

 nameTextField.delegate = self

さらにソースコードの最後にデリゲートメソッドを追加します。
下記のコードを追加してください。

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    // keyboardを隠す
    textField.resignFirstResponder()

    return true
  }

このメソッドはリターンキーが押されたというイベントが発生した時に実行されます。
他にも色々なイベントを受け取れます。UITextFieldDelegateで調べてみて下さい。
入力中に表示されていたキーボードを隠す処理を入れました。

実行するとリターンキーを押した時にキーボードが隠れれば成功です。

入力した値の保存と表示

設定画面にUserDefaultsというアプリ内の保存領域の情報を画面に表示する処理を書きました。

    if let name = UserDefaults.standard.value(forKey: "name") as? String {
      nameLabel.text = name
    }

"name"という名前のキーで情報があれば表示しています。
同じように名前の入力欄も情報があれば表示するよう変更します。

先程のviewDidLoad関数の nameTextField.delegate = selfの下に次の行を書き加えて下さい。

    // UserDefaultsの情報を画面にセットする
    if let name = UserDefaults.standard.value(forKey: "name") as? String {
      nameTextField.text = name
    }

入力された内容の保存処理も記述します。
先程のtextFieldShouldReturn関数の
textField.resignFirstResponder()の下に次の行を書き加えて下さい。

    // 入力された内容を保存する
    UserDefaults.standard.set(textField.text, forKey: "name")

"name"という名前のキーで保存しました。
実際のアプリの処理では、入力内容のチェックを行ったり、
余計なスペースを取り除いたり、保存ボタンを付けたりすると思いますが
ここではサンプルのため無条件にリターンキーを押されたら保存することになります。

▶ボタンを押して実行してみます。

何か入力してリターンキーを押します。
前の設定画面に戻ると名前の右側に入力したものは表示されていません。
あらためて名前のセルを押して入力画面に遷移すると、
先程入力した文字が入力欄にセットされていると思います。

設定画面に戻った時に表示されなかったのは、
UserDefaultsの変更があった時に変更通知を受け取る処理が記述されていないからです。

もう一度▶ボタンを押して実行すると今度は表示されるはずです。

設定画面でUserDefaultsの変更があった時に画面を更新する

設定画面を編集してUserDefaultsの変更通知を受け取る処理を記述します。

SettingsTableViewController.swiftを開きます。
viewDidLoadの「super.viewDidLoad()」の後に次のコードを追加してください。

    // UserDefaultsの変更を監視する
    NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange),
                                           name: UserDefaults.didChangeNotification, object: nil)


ソースコードの最後の「 } 」の直前に次のコードを追加してください。

  @objc func userDefaultsDidChange(_ notification: Notification) {
    // UserDefaultsの変更があったので画面の情報を更新する
    if let name = UserDefaults.standard.value(forKey: "name") as? String {
      nameLabel.text = name
    }
  }

  deinit {
    // UserDefaultsの変更の監視を解除する
    NotificationCenter.default.removeObserver(self, name: UserDefaults.didChangeNotification, object: nil)
  }

既にUserDefaultsに保存済なので一度アプリをアンインストールしてから
▶ボタンを押して実行してみます。

入力後に設定画面に戻ると入力内容が表示されます。

f:id:sakura_bird1:20180309012054p:plain:w400

解説は以上となります。

全体のソースコードはこちらにあります。
github.com


以上です。

iOSでRealmのデータファイルの場所の見つけ方

初期データのあらかじめ入ったRealmのファイルを用意しておき、
アプリに組み込んで使いたいと思っています。
それにはデータが入ったDBのファイルが必要です。
Realmの保存場所を特定する方法をメモしておきます。

前提

環境はXcode9.2、Swift4.0を使用しています。
初期データ作成用のXcodeプロジェクトを作っておきます。
実機かシミュレーターにRunしておきます。

シミュレーターにインストールした場合の場所

    // DBのファイルの場所
    print(Realm.Configuration.defaultConfiguration.fileURL!)

このコードでファイルパスを表示してくれます。
f:id:sakura_bird1:20180124152523p:plain

これをコピーします。

finderを開いてCommandキー+Shiftキー+Gを押します。

先ほどのパスを貼り付けます。
f:id:sakura_bird1:20180124153944p:plain:w200

先頭の「file://」は削除して移動します。

実機にインストールした場合

Xcodeのメニューから Window > Devices and Simulators を選択します。

実機にインストールされているアプリが一覧で表示されます。

アプリを選択します。

左下の設定アイコンをクリック > “Download Container…“を選択します。
f:id:sakura_bird1:20180124153205p:plain:w300


保存ダイアログが開きます。プロジェクトルートがデフォルトの保存場所になっています。
◯◯.xcappdataという名前がセットされているのでそのまま保存します。

Finderで保存した場所を開きます。
◯◯.xcappdataを右クリックして「パッケージの内容を表示」(英語表示の場合「“Show Package Contents”」)をクリックします。
f:id:sakura_bird1:20180124153450p:plain:w300

ここにあります。
AppData / Documents / default.realm
f:id:sakura_bird1:20180124153600p:plain:w300

以上です。