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

SwiftでRealmを使用する方法について

Realmをインストールする

Realmを使用するために、CocoaPodsを使用してインストールを行います。
PodFileにpod 'RealmSwift'を追記し、pod installでインストールします。

pod 'RealmSwift'

Swiftではimport RealmSwiftでインポートします。

import RealmSwift

モデル定義

class モデル名: Object { }でモデル定義を行います。
@objc dynamic varで、プロパティ定義を行います。

import UIKit
import RealmSwift

class モデル名: Object {
    @objc dynamic var プロパティ名1 : 型名 = 初期値
    @objc dynamic var プロパティ名2 : 型名 = 初期値
}

データの追加

realm.add(モデル名(value: 値))で、データを追加できます。
事前に、プロパティに対する値を入れている必要があります。

let realm = try! Realm()

let object = モデル名()
object.プロパティ名1 = 値1
object.プロパティ名2 = 値2

try! realm.write {
     realm.add(モデル名(value: object))
}

データの更新

.filter等で対象のObjectを取得し、write()でデータの更新を行います。

let realm = try! Realm()

let results = realm.objects(dayList.self).filter("プロパティ名1 == 値1 AND プロパティ名2 == 値2").first

try! realm.write {
     results!.プロパティ名1 = 値3
}


データの削除

.filter等で対象のObjectを取得し、write()でデータを削除を行います。
.delete()で対象のみdeleteAll()で全て削除します。

let realm = try! Realm()


let results = realm.objects(toDoList.self).filter("name == 'Michael Jeffrey Jordan'")

//
try! realm.write {
realm.delete(results)
}

データが全くない場合初期値を追加する

データがない場合、データを読み込みに失敗します。
そのため、以下のようにして、データがない場合のみ初期値の追加をする必要があります。

let realm = try! Realm()

// データが1つもない場合
if realm.objects(モデル名().self).first == nil {
     let object = モデル名()
     object.プロパティ名1 = 値1
     object.プロパティ名2 = 値2

     try! realm.write {
          realm.add(モデル名(value: object))
     }
}

モデルの変更をした場合

プロパティ名の追加等を行った場合、Realmの呼び出しでエラーになります。
そのため、変更があった場合スキーマの情報を更新させエラーが発生しないようにする必要があります。

// プロパティ名の変更があった場合、schemaVersionの値を変更する
let config = Realm.Configuration(
      schemaVersion: 1,
      migrationBlock: { migration, oldSchemaVersion in})

Realm.Configuration.defaultConfiguration = config
config = Realm.Configuration()
config.deleteRealmIfMigrationNeeded = true

参考

https://realm.io/jp/docs/swift/latest/

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

iOSDC「あなたの知らない連絡先の世界」「詳解Storyboard」補足&参加した感想

iOSDC Japan 2020で発表してきた内容でいくつか受けた質問の答えや補足&参加した感想になります

あなたの知らない連絡先の世界

はてなブックマークで紹介されたらしく、えらい数見ていただいてます。

https://speakerdeck.com/coe/anatafalsezhi-ranailian-luo-xian-falseshi-jie

vCard 3.0(iOS)と vCard 2.1(Android)

Androidで取得したvCardは、Quoted-printableがかかっています。

iOS

BEGIN:VCARD
VERSION:3.0
PRODID:-//Apple Inc.//iPhone OS 13.6//EN
N:日向;強;搩;ドクター;三世
FN:ドクター 強 搩 日向 三世
END:VCARD

Android

BEGIN:VCARD
    VERSION:2.1
    N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E6=97=A5=E5=90=91=E7=81=98;=E5=BC=B7;=46;=44=72;=4A=72
    FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=44=72=20=E6=97=A5=E5=90=91=E7=81=98=20=46=20=E5=BC=B7=20=4A=72
    END:VCARD

PersonNameComponentsFormatterはサーバーサイドSwiftで使える?

使えませんでした。NSUnsupportedでした。
https://github.com/apple/swift-corelibs-foundation/blob/2a5bc4d8a0b073532e60410682f5eb8f00144870/Sources/Foundation/PersonNameComponentsFormatter.swift

Objective-Cでしか使えないメソッド

本編で紹介した enumeratorForChangeHistoryFetchRequest:error: の他にも、
連絡先を取得するenumeratorForContactFetchRequest:error: もObjective-Cでしか使えません。
SwiftUI? Combine? 甘
https://developer.apple.com/documentation/contacts/cncontactstore/3294191-enumeratorforcontactfetchrequest?changes=_3&language=objc

詳解storyboard

https://speakerdeck.com/coe/xiang-jie-storyboard

SceneDelegateのリストア

今回発表されていた iPadOSDC: Multiple Windows で解説されています。
https://speakerdeck.com/hironytic/ipadosdc-multiple-windows

Appleのサンプルドキュメントもあります。
https://developer.apple.com/documentation/uikit/uiscenedelegate/restoring_your_app_s_state

Storyboardの分割

WWDC 19のGreat Developer HabitsにてStoryboardの分割に触れています。
その他にもエンジニアにとって重要な話をしているので、このセッションは非常におすすめです。
https://developer.apple.com/videos/play/wwdc2019/239/

まばたきの検出

本編では省略したまばたきの検出コードですが、例えば AVCaptureVideoDataOutputSampleBufferDelegate でCMSampleBufferから顔を検出し、目を閉じている、開いているを検出して判定するとまばたきの検出が行えます。
以下のコードは、両目を閉じている人を検出してアクションを起こす例です。まばたき検出はもうちょっとコードが必要になります。

    // MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
    func captureOutput(_ output: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        let ciImage: CIImage = CIImage(cvPixelBuffer: pixelBuffer)

        guard let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) else {
            return
        }

        let faceFeatures = faceDetector.features(in: ciImage, options: [
            CIDetectorSmile:true,
            CIDetectorEyeBlink:true
        ]) as! [CIFaceFeature]

        let closedEyes = faceFeatures.filter { (faceFeature) -> Bool in
            return faceFeature.leftEyeClosed && faceFeature.rightEyeClosed
        }
        if !closedEyes.isEmpty {
            self.sendActions(for: .primaryActionTriggered)
        }
    }

個人的な感想

よかったら二つやりませんか?との打診を受けて、Storyboardだけやろうかなと思ったんですが、せっかくだから俺はどちらとも選ぶぜという勢いのみでやってみました。
結果的には本命のStoryboardではなく連絡先が好評?だったので、フェイルセーフが働いて良かったです。
セッションは20分コースと40分コースがあって、40分喋り続けるのきついなと思ってチキって20分にしたんですが、「持ち時間が40分もらえる」という考えであれば、次出られるのであれば長い時間はありかな、と思いました。Storyboardは説明がいっぱいいっぱいだったので小粋なトークが挟めませんでした。
なんにせよ、見ていただいた方、ご清聴ありがとうございました!ご清聴?

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

部品を画面の中央に配置する方法

スクリーンショット 2020-09-22 14.12.52.png

(1)AutoLayoutの部分の左から2番目のアイコンをクリックします。
(2)以下2つにチェックをいれる
Horizontally in Container (cf. Horizontal 水平な)
Vertically in Container  (cf. Vertical 垂直な)
(3) 「Add 2 Constraints」をクリック
→これで自動的に部品が画面の中央に配置されます

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

iOSDC2020に参加しました

はじめに

iOSDC2020が昨日無事終了しました。
今回の開催はニコニコ生放送での初のオンラインということで、どういう感じになるのだろうと思っていたのですが、グリーンバックを使っていたり、ニコ生のコメント機能でリアルとはまた違った感じで盛り上がる、家でリラックスしながら見れるなど、オンラインならではのいいところがたくさんあり、とても良かったです。

以下自分の気になったセッションを簡単にまとめていきます

気になったセッション

サムネイルをクリックすることでスピーカーの皆様が上げてくださったSpeakerDeck/SlideShareへ移動できます。

今日から分かるAVAudioEngineの全て

Day0/TrackA
スピーカー:meteorさん

thumbnail

meteorさんのトークでは
・iOSのAudio周りをあまりしらない方のためのAudioUnit/AVFoundationの解説
・実際のコードを例に挙げながらAVAudioEngineなどの基本的な使い方
・RMSの取得
WORLDを使ってボイスチェンジャーを実装して(ラッパーであるWorldInAppleのポイントを解説)みるという高度な話をされていました。

最後の方は完全にはついていけていなかったのですが、自分も現在音声処理のアプリの案件に携わっているので、とても復習になり、またmeteorさんのトークは録画感を感じさせず実際に生放送で話されているみたいで、いいセッションでした。

iOSリジェクト戦記 ~リジェクトされないための課金ページ~

Day1/TrackA
スピーカー:HiromuTsurutaさん

thumbnail

HiromuTsurutaさんのトークでは
・課金ページで守らなければいけないこと
・課金ページにはどういうタイプがあるのか
・注意文言/金額表記/無料表記で実際にリジェクトされたときの問題点/対策など
・いろいろなアプリの過去と今の課金ページの比較
・リジェクトを切り抜けるための回避策(グレーゾーン)
をわかりやすく説明されていました。

個人的にはAppleの課金ページでは無料を大きくして、値段を小さくしているのでガイドラインを守っていないというオチが面白かったです。
課金(サブスクリプション)ページのリジェクト理由など、深く観察されている+スライドの作り込みすごい+トークの上手さもあり、とても完成度が高いセッションだと思いました。

スピーカーのHiromuTsurutaさんが以前書かれたアプリアイコンについての記事もとても完成度が高くおすすめなのでぜひ興味のある方は読んでみてください

「アプリアイコン」を考察してみたお話

エラーアーキテクチャ設計について考えてみる

Day1/TrackD
スピーカー:きちえもんさん

thumbnail

きちえもんさんのトークでは
・iOSアプリでエラーハンドリングの改善
・Androidアプリでエラーハンドリングの改善
・エラーアーキテクチャ設計について
を話されていました。

iOSでのエラー処理では共感できるところが多く、またその解決法もenumを使うなどなるほどな〜と勉強になるところが多かったです。エラーアーキテクチャについてどのような姿を目指すかの中でユースケースについての説明の時に、ついてユーザーが異なる操作を行った/何か悪いことが起こったに焦点を当てた事を雨の日のシナリオという表現/喩えがとてもわかりやすく、スライドも綺麗に纏まっていて、とても見易かったです。
ユースケース駆動については初めて知ったので、自分でも調べていこうと思いました。

Github ActionsでiOSアプリをCIする個人的ベストプラクティス

Day1/TrackB
スピーカー:uhooiさん

thumbnail

uhooiさんのトークでは
前半に
・CI
・Make
・GitHub Actions
の説明を行い、後半に実際にHANDSON形式で行ってみるという形でした。

CI,Make,GitHub Actionsなどをuhooiさんの言葉/イラストでわかりやすく説明してくれており、HANDSONではGitHubActionsの導入を実際にやってみるという形で見せながらわかりやすく解説してくれていました。実際にトークをみながら導入を試していた方もいらっしゃったようです。
個人的にはスライドの途中で出てきた手書きイラストが味があって好きでした。

Swiftで始める静的解析

Day2/TrackD
スピーカー:まつじさん

thumbnail

まつじさんのセッションでは
・そもそも静的解析とは
・静的解析はどのように行われているのか
・実際にSwiftSyntaxを用いて、構文木を解析してみる。
についてお話しされていました。

自分はこのセッションを聞くまではソフトウェア工学をあまり知らず、静的解析についてもなんとなくSwiftLintをがあるということしかわかっていなかったのですが、このセッションで静的解析がどのような仕組みで行われているのかというトークを聞いていて、これはどうなんだ?と思った所を次の話でまつじさんが解説してくれて、静的解析への理解が深まるセッションでした。

テストコードが増えるとバグは減るのだろうか? - 「0% → 60.3%」で見えた世界の話

Day2/TrackD
スピーカー:ahirustarrrさん

thumbnail

ahirustarrrさんのセッションでは
・テスト実装に至る背景
・テストコードがなかったプロダクトにテストが実装されて、感じたメリット/デメリット
・組織開発体制に適したテスト手法
・テストが増えるとバグは減るのか
についてお話しされていました。

トークの背景、内容などがとても共感できる内容であるあると思いながらトークを聞いていました。
テスト導入に近い話は普段、他の会社の話はあまり聞くことがなかったので、とてもいい機会でした
テストを導入するメリット/デメリットを詳しく解説してくれていて、これからテスト導入しようかなという人にもみて欲しいなというセッションです。
Twitterでテストコードを書いた経験がないとどうテストを書けばいいのかわからない的な意見もみられ、自分もまだ浅い方なのでなるほどなと思いました。

イベントを通しての感想

他にも良かったセッションやまだ見れてないセッションはいくつもありますのでこの後視聴しようと思います。
気になったかたは後日YouTubeに動画が上がるそうなので視聴して、来年参加してみてはどうでしょうか?

運営スタッフの皆様、スピーカーの皆様ありがとうございました。

参考リンク

Qiitaの記事にSpeaker DeckやSlideShareのサムネ付きリンクを貼る方法

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

VSCodeでSwiftの環境構築をする方法

はじめに

VSCodeでSwiftを使うための環境設定の方法を丁寧に紹介します。
競技プログラミングでSwiftを使いたい、見慣れたVSCodeで使いたい、Xcodeで標準入力の仕方がよくわからないといった方におすすめです。

開発環境

OS: macOS Catalina Version 10.15.6
Visual Studio Code (VSCode): Version 1.49.1

手順

  1. Xcodeのインストール
  2. VSCodeのインストール
  3. NodeとNPMのインストール
  4. SourceKit-LSP Extension for Visual Studio Codeのインストールとビルド
  5. SourceKit-LSPの設定

1. Xcodeのインストール

Xcodeがすでにインストールされている場合は飛ばして構いません。
Xcodeのインストール方法: https://techacademy.jp/magazine/1409

2. VSCodeのインストール

VSCodeがすでにインストールされている場合は飛ばして構いません。
VSCodeのインストール方法: https://qiita.com/watamura/items/51c70fbb848e5f956fd6

3. NodeとNPMのインストール

Homebrewを使ってnodeをインストールします。同時にnpmもインストールされます。

$ brew install node

インストールされたことを確認するために以下のコマンドを実行してみてください。

$ npm --version                                                            
6.14.8

4. SourceKit-LSP Extension for Visual Studio Codeのインストールとビルド

コマンドラインからSourceKit-LSPをクローンします。

$ git clone https://github.com/apple/sourcekit-lsp.git

次にインストールされたフォルダへ移動します。

$ cd sourcekit-lsp/Editors/vscode/

拡張パックをビルドします。

$ npm run createDevPackage

ビルドしたものをインストールします。

$ code --install-extension out/sourcekit-lsp-vscode-dev.vsix

5. SourceKit-LSPの設定

VSCodeでSwiftのファイルを実行しようとした際に以下のエラーが出た場合には、VSCodeの設定を変更します。

Couldn't start client SourceKit Language Server

Cmd+Shift+Pでコマンドパレットを開いたあとに
基本設定: 設定(JSON)を開く (Preferences: Open Settings (JSON)"
を選択します。
そしたら、すでにあるJSONに以下の文章を追加しましょう。(書き換えではなく追加です。)

"sourcekit-lsp.serverPath": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp"

6. 確認

hello_world.swiftというファイルを作成しましょう。
作成したファイルに以下のコードを記入してみます。

hello_world.swift
print("Hello, world!")

ターミナルで以下のように書くと実行することができます。

swift hello_world.swift

または、Control+Option+nでも実行することができます。
ちなみに実行結果は

Hello, world!

です。

7. 型推論

今のままでは型推論がされない(と思う)ので、以下のように実行してください。ファイルをまず開きます。左下に

(HDの名前) > ユーザ > (あなたのユーザ名) > ...

と表示されていると思います。その中から、(あなたのユーザ名)をクリックします。以下順番にファイルを開いていきます。
sourcekit-lspを開きます。
Editorsを開きます。
vscodeを開きます。
outを開きます。
sourcekit-lsp-vscode-dev.vsixというファイルが有ることを確認してください。
確認できたらこのページを開きっぱなしにしておきます。
VSCodeの拡張機能タブから右上の・・・を選択し、VSIXからのインストールをクリックします。
VSIXからのインストール.png
すると、インストールするファイルを選ぶ画面が表示されるので先程開いたsourcekit-lsp-vscode-dev.vsixをドラッグ&ドロップします。
最後に、開いたファイルをインストールしましょう。
これで型推論ができるようになりました!

8.C言語やC++のコンパイルにsourcekit-lspを用いたくない人へ

lsp-sourcekitのページには以下のように、Swiftだけでなく、C、C++、Objective-Cにも対応していると書かれています。
lsp-sourcekit is a client for SourceKit-lsp, a Swift/C/C++/Objective-C language server created by Apple.
そのため、今までC言語やC++で使っていたコンパイラでは動くのにlsp-sourcekitでは動かないということが発生する可能性があります。そんなときは、Swiftを使うファイルをC言語、C++を使うファイルとは分けた上で、Swiftを使うワークスペースだけでlsp-sourcekitの拡張機能を有効にしましょう。
① SourceKit-LSPを無効にする
スクリーンショット 2020-09-22 11.23.49.png

② 再読み込みを行う

スクリーンショット 2020-09-22 11.26.47.png

③ 拡張機能→SourceKit-LSP→有効にする→有効にする(ワークスペース)

スクリーンショット 2020-09-22 11.27.38.png

9. 参考文献

https://nshipster.com/vscode/
https://medium.com/swlh/ios-development-on-vscode-27be37293fe1
https://scior.hatenablog.com/entry/2019/10/27/215827

10. 終わりに

私は、まだまだ初心者なのですが参考文献に上げた3つのページを参考にVSCodeに導入してみたらうまく行ったので、共有させていただきました。
間違っているところがあったらご指摘ください。また、詳しい人がいたらぜひ記事を書いてください。私は、日本語でまとまっている記事を見つけ出すことができず、苦労しました...!

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

enumを使ってリテラルをまとめる

こんにちは。
最近自分が書いているCodeの品質を上げるために日々模索中です。
最近よく思うのは stringの文言とか、identifierを直書きしたりとか、そういうのしたくないなと思うようになり、
良い書き方ないかなと考えてCode読みあさって考えてみたら良さげな実装を思いついたので、記事にしようと思いました。

結論

enumで定義してしまえばまとまっててわかりやすいんじゃね?

よくある実装1

  • UITableViewのidentifierとか
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
    /// ...
    return cell

よくある実装2

private let cellId = "hogeCell"
/// ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! TableViewCell
    /// ...
    return cell

上記のよな感じで実装するとなんかいけてないし、個人的に直書きしたくないので(よきせぬ不具合を出したくない)ので以下の実装にしてみました。

実装

enum IdentifierType {
    static let segueId = "hogeSegue"
    static let cellId = "fugaCell"
    static let nibId = "HogeFugaTableViewCell"
   }

こんな感じで定義して、

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: IdentifierType.fugaCell, for: indexPath) as! TableViewCell
    /// ...
    return cell

とか

let nib = UINib(nibName: IdentifierType.nibId, bundle: nil)
hogeTableView.register(nib, forCellReuseIdentifier: IdentifierType.cellId)

みたいにして定義してあげれば、どこの何が定義してあるのかとてもわかりやすいし、直書きしなくてより安全なのではと思いこのような実装にしてみました。

まとめ

今回は、さくっとできてそれなりにまとめられて、すっきりできて、より安全に、より可読性も上がるなと個人的に思い上記の実装をしてみました。

しかし、より大規模アプリとかになると上記のような実装だけだといろいろ足りないし、より広範囲でまるっとサポートしてくれたらと思うので、より安全性や品質を高めて行ったり、楽したかったりしたらR.swiftがとても優秀なのでそれ使った方が良いと思います。
あくまで上記は小規模アプリとかで、ライブラリ入れなくても良いくらいの規模感のアプリなら、上記で対応しても良さそうに思いました。

読んでいただきありがとうございました!
もっと良い実装とか他何かありましたらコメントいただけたら涙が出るくらい喜びます!!

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