20210122のiOSに関する記事は11件です。

Flutterとはなんぞや。〜html、cssを見たくないけどモダンなUI組みたいあなたへ〜

お久しぶりです!やびーくでっす! :sunny:
本日は、FlutterでiOSとAndroidのアプリを開発する方法についてお話しします!

目次

  • Flutterとは
    • プログラムの一元管理
    • HTML、CSSを意識しないモダンなUI構築
    • 豊富なライブラリとホットリロード
    • 実際に体験したい方へ
    • 開発チームメンバーの声
    • 参照記事

Flutterとは

FlutterはiOSとAndroid両方で動作するスマホアプリを作成するためのDart言語のフレームワークです!

一部ハードウェアに依存するコードはそれぞれjavaやobject-cなどで記載する必要がありますが、
基本的なプログラム・UIは共通化することができるので、iOSとAndroid両方のアプリケーションを作る場合のプログラムソースをほとんど一元化することができます。

プログラムの一元管理

画像を元に説明します。
※あくまで触ってみて感じたイメージなので参考までに!
 2021-01-12 19.31.38.png

Flutterが担うのが①〜③の部分です。

①共通プログラム

 UI、基本的なプログラムソース

②③iOSネイティブコード/Androidネイティブコード

 ライブラリなどで対応できないが使用したいハードウェア機能(カメラやセンサー系など)がある場合
 ライブラリは豊富にあるので基本的にはライブラリで補完できるとも言われています。

実際に業務の中で、ハードウェアのセンサー部分の機能を利用しましたが、
基本的に②と③のネイティブコードは書く必要がなかったです!

ネイティブコードを書く場合にも以下のように最初から2つのプラットフォーム上で動かすことを前提として、ディレクトリが構成されているのでgitなどのソース管理も楽なんです!

android/    Android用のソースフォルダ
ios/        iOS用のソースフォルダ
>>>省略

HTML、CSSを意識しないモダンなUI構築

Flutterでは、Widgetという概念で、UIを構築します。
htmlやcssをあまり意識しないで、UIを構成することができます。

Flutter マテリアルコンポーネント
 2021-01-22 20.51.24.png

公式サイトにマテリアルデザインのUIコンポーネントが部品として公開されていて
その部品はどの部分のものか、サンプルコードなどが準備されています。

 2021-01-22 20.52.35.png

プログラマは使用したい部品を探してサンプルコードをもとに
組み立て作業を行うだけでシンプルかつわかりやすいデザインのUIが構築できるんです!
もちろんホットリロードにも当たり前のように対応!デバッグモードであれば、簡単に設定して操作が可能です!
Flutter公式 ホットリロードについて

豊富なライブラリ

Flutterで開発してみて驚いたのが、ライブラリの豊富さ!

Flutterライブラリ集
 2021-01-22 21.15.27.png

「加速度センサーはハードに依存するだろうから、ネイティブコード書かないといけないんだろうな〜」なんて思っていたのにあらびっくり!
ライブラリをインポートしてメソッド呼び出してすぐセンサ系の値の取得が可能でした!

今はむしろどんな時にネイティブコードが必要なのか知りたくなってます(笑)
ご存知の方はそっと教えてください。

実際に体験したい方へ

FlutterのWidgetとはなんぞやっていうのが手軽に確認できるツールも紹介しながら、CodePenのデフォルトソースはこんな感じです。

CodePen

環境構築をすっ飛ばしてFlutterの雰囲気を確認可能なので、気になった方はお試しください。
 2021-01-19 9.38.44.png

FlutterのWidgetではhtmlやcssを直接書かずに、プログラムっぽく組み合わせて勝手にモダンなUIに変換してくれます!めちゃくちゃ作りやすいですね!

コードなんて書きたくない!デザインしたあと、ソースどんな感じなの?って思う方は以下のサービスでお試し!

Flutter Studio
 2021-01-19 9.40.58.png

Flutterの公式のかっちょいい動画があるので
時間がある方はぜひ見てみてください。作成できるUIイメージが具体的になると思います。

Flutter公式Youtube

チームメンバーの声と総評

最後に実際に開発に携わったメンバーからのコメントをご紹介します。

「フロントエンドの実装が苦手すぎて、作業すると眩暈がするんだけど、FlutterのWidgetは要素をしっかり指定して書いてあげれば勝手にいい感じのUI出来上がってて、めちゃくちゃ良かった!」
→Windowsアプリ開発経験多 H.Gさん

フロントエンドが苦手な人でも綺麗なUIを簡単に構築できるというのはデザイナーやコーダーがいないチームにはメリットですね。

「htmlやcssに慣れている人は最初とっつきにくいかもしれないけど、理解すると扱いやすく感じた。UIが綺麗にまとまるのが良い」
→フロント6割:バックエンド4割経験者 T.Kさん

逆にフロントエンドに慣れている人はWidgetの独特な書き方に慣れるまでは少し学習コストがかかるかもしれないです。

しかし、クロスプラットフォームアプリを構築する場合に、ソースの一元管理が可能なのは、それ以上のメリットもあると私は考えてます!
UI構築の際は、いろいろなツールを使って自動的にソースを生成したりするなど、工夫して利用すれば、工数削減や、デザインの統一などFlutterが提唱している恩恵をより受けることが可能だと思いますので興味のある方はぜひ調べてみてください!

長くなりましたが、最後までお読みいただきありがとうございます。
1月中にさらに1本投稿予定なのでお楽しみに〜!:relaxed::v:

参照記事/リンク

・Flutterを大好きになってしまうカラクリ
・Flutter公式サイト
・Flutterライブラリ集
・CodePen
・Flutter Studio
・Flutter公式Youtube

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

【RxSwift】Reactive の Extension を作成する際にメモリリークが発生した

環境

  • Xcode 12.3
  • RxSwift 5.1.1

目的

  • TabTestViewControllerself.viewDidLayoutSubviews() 呼び出しを検知しその際の self.index を流す Observable<Int> を作成したい
TabTestViewController.swift
// こんな感じで利用する currentIndexDidChange を Extension で実装
self.rx.currentIndexDidChange
    .subscribe(self.indexSubject)
    .disposed(by: self.disposeBag)

当初実装

  • 以下のように実装するとメモリリークが発生する
TabTestViewController+rx.swift
extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // メモリリークが発生
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { _ in base.currentIndex }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}

原因

  • base がクロージャ内部で強参照されていることによる

間違い: self を弱参照しようとした

  • 「クロージャの中では selfを弱参照」と手癖で実装しようとしたところコンパイルエラー
    • Reactive<Base> は構造体のため weak が使えない
TabTestViewController+rx.swift
extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // 'weak' may only be applied to class and class-bound protocol types, not 'Reactive<Base>'
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak self] _ in

                guard let self = self else { fatalError() }

                return self.base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}

解決: base を弱参照とする

  • TabTestViewController はクラスのため weak で弱参照することができる
TabTestViewController+rx.swift
extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // viewDidLayoutSubviewsのタイミングでcurrentIndexの変化を検知する
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak base] _ in

                guard let base = base else { fatalError() }

                return base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSショートカットAppでInstagramの画像動画保存機能を作ってみた

はじめに

Instagramの写真や動画を保存できるサイト(Instadownloderなど)は存在しますが、投稿リンクをコピーしてサイトに貼り付けて、実行ボタンを押して、表示された画像をダウンロードといった手順が煩わしいと感じたためショートカットAppでの作成に取り掛かりました。このショートカットでは、投稿リンクをコピーして実行ボタンを押すだけで写真や動画のダウンロードまで行ってくれることを目指しました。

成果物

実際に作成したショートカットはこちらからダウンロードできます。
ダウンロードしたショートカットを使用するためには、設定から「信頼されていないショートカットを許可」を有効にする必要があります。
設定方法は、「設定>ショートカット>信頼されていないショートカットを許可」から行うことができます。尚、なんらかのショートカットを事前に一度実行させていないと信頼されていないショートカット許可を有効にできない仕様みたいなので、既存のショートカットを一度実行してから行うことをおすすめします。

このショートカットでできること・できないこと

できること できないこと
- Instagramの公開アカウントの写真・動画・リールの保存
- 保存したいファイルの選択
- 非公開アカウントの写真・動画・リールの保存
- instagram以外のサイトのファイルの保存

ショートカットAppとは

iPhoneやiPadの複数の機能や操作を自動化してくれるiOSアプリのことを指します。
例えば、現在聴いている曲の内容を取得して、ワンタップでtwitterの文章を作成してくれたり、再生回数の多かった上位25曲のプレイリストを作成してくれたり、ミュージックのデータから音楽クイズを作成するなどのお遊び機能までできちゃいます。

スマートホームデバイスを使い、ショートカットAppに登録しておくと家電の操作などもワンタッチや声での操作で行うことができます。
僕はNature Remo miniを使って部屋のライトとエアコンの操作を行ったりしています。

Instagramの画像動画保存ショートカットの概要

ここでは、Webの仕組みを利用しています。Webでは暗号化などがされていなければ基本的に任意のデータまでアクセスすることができます。そのため、任意のデータがあるリンクを見つけてそこにアクセスすればいいわけです。

Webの検証を使ってInstagramのサイトの中身を見てみると...
スクリーンショット 2021-01-22 14.14.46.png

実際に画像のリンクが載っていることがわかります。このリンクに飛んでみると画像が表示されること、またその画像が保存できることが確認できるはずです。

そこで、今回作成したショートカットではこの仕組みを利用して投稿されている画像や動画のリンクを取得し、そのリンクからデータを保存するという仕様になっています。

ショートカットの中身

このショートカットは大きく6つのブロックとなっています。

  1. クリップボードを取得し、Instagramのリンクか判定、でなければアラートを出して終了
  2. クリップボードの内容を取得し、HTMLを作成
  3. 画像や動画のリンクをターゲットとし、一致した場合は随時、リストに格納
  4. 格納されたリストから'\u0026'を'&'に置換(iOSでは&がUnicodeにエンコードされていたため)
  5. 写真や動画が1つだけだった場合と複数ある場合で条件分岐し、結果を写真動画リストに格納
  6. 写真動画リストから任意のファイルを選択し、選択されたファイルを保存

それぞれのブロックについて説明します。

1. クリップボードを取得し、Instagramのリンクか判定、でなければアラートを出して終了

ここでは、クリップボードに保存されているデータがInstagramの投稿リンクでなかった場合、投稿リンクをコピーするように促します。
IMG_0662.jpg

2. クリップボードの内容を取得し、HTMLを作成

投稿リンクからHTMLを取得します。
IMG_0663.jpg

3. 画像や動画のリンクをターゲットとし、一致した場合は随時、リストに格納

画像のリンクの前には、"display_url":"https://scontentという文字列が含まれているという規則を利用して、正規表現を用いて文字列の検索を行います。
また、基本的には1080pの画像となっているため、さらに1080x1080と一致する文字列を検索します。検索に引っかかった場合は取得リンクを取得リンクリストに追加します。
IMG_0664.jpg

一致しなかった場合は750pの画像のリンクを検索し、一致した場合は取得リンクリストに追加
750pの画像リンクも一致しなかった場合は、ピクセルを指定せずに検索して、取得リンクリストに追加します。
IMG_0665.jpg

動画のリンクも検索して一致した場合は取得リンクリストに追加します。さらにリールのサムネイルを設定している場合もあるので、サムネイルも保存できるようにサムネイルのリンクも検索をかけて取得リンクリストに追加します。
※ここでは、サムネイルを動画の前に保存したいという謎のこだわりがでたため、一旦動画のリンクを動画取得リンクに格納して、サムネイルのリンクを取得リンクリストに追加した後、動画取得リンク取得リンクに格納しています。
IMG_0666.jpg

4. 格納されたリストから'\u0026'を'&'に置換

iOSでHTMLを表示した時&がUnicodeでエンコードされていたため、リンクに飛ぶことができなかった。
そのため、\u0026&に置換することで有効なリンクに変換している。
デコードする方法はよくわからなかったため、置換で対応した。
IMG_0667.jpg

5. 写真や動画が1つだけだった場合と複数ある場合で条件分岐し、結果を'写真動画リスト'に格納

画像が一枚の時は取得するリンクが1つだが、複数会った場合投稿画像N枚に対してN+1つリンクが取得されるようになっていたため、画像一枚と複数ある場合で条件分けを行なっている。
画像が複数あった場合は、2つ目以降の項目から最後までを写真動画リストに追加する仕様にしています。
IMG_0668.jpg

6. 写真動画リストから任意のファイルを選択し、選択されたファイルを保存

これまでの作業で写真動画リストに取得したいファイルのリンクを格納したため、'リストから選択'関数を用いて、任意のファイルを選択できるようにしている。
最後に選択された項目を'写真アルバムに保存'関数を使って写真フォルダに保存します。
IMG_0669.jpg

ショートカットの内容は以上です。

感想

いままで簡単なショートカットは作ったことがありましたが、凝ったショートカットは初めて作ったのでちゃんと動かせたときは興奮しました。特にファイルを選択して保存するという機能は一つの関数だけで行え、思ったよりも簡単に実装できたのが驚きました。また、ショートカットの関数も充実しており、ほかにもさまざまなことに対応できそうということで、他のショートカットも作ってみたく思いました。気になった方は是非ショートカットを作ってみてください。最後までご閲覧いただきありがとうございました。

参考文献

[1] iPhone『ショートカット』アプリが便利!使いこなし方やおすすめの設定法を紹介します (TIME & SPACE by KDDI)
[2] iPad,iPhoneショートカットまとめ【あなたもすぐ使える】(YMK-BLOG)

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

XcodeのComponentsのSimulatorがdownload済みなのに使えない時の対処法

Xcodeをuninstallしてinstallしなおした時に、前のXcodeの情報が残っていたのでその対処法を備忘録として残しておきます。

現象

  • Add additional Simulators または Window -> Devices and Simulators -> Simulators -> + でsimulatorを追加しようとしたところ、 OS Versionの選択にiOS 10.3が表示されない

スクリーンショット 2021-01-22 13.48.37.png

  • Download Simulators または Xcode -> Preference -> Components で確認するとiOS 10.3 Simulatorはダウンロード済みになっている

スクリーンショット 2021-01-22 13.48.37のコピー.png

つまり
ComponentsのSimulatorのOSがDL済みになっているのに、Simulator作成画面で選択できない

解決策

  • ~/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 10.3.simruntime を削除
  • /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 10.3.simruntime を削除

"~/Library" と "/Library" があるので注意

無事ComponentsのSimulatorのチェックマークが外れたのでDLしなおすことができた
(未検証だが、 /Library のsimruntimeを ~/Library の方に移動させれば再ダウンロードしなくても大丈夫だったかもしれない)

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

【Model I/O】MDLMeshオブジェクトから頂点データを取得する方法

Model I/Oフレームワークの、MDLMeshオブジェクトから頂点の情報を取得するのが面倒だったので、メモ。

参考:
Read vertex positions with Model I/O
https://gist.github.com/algal/8e31ce035af0aafebc3736661ae9e3cd

mdlMeshにMDLMeshオブジェクトの値が入っているとして、これをXcodeのデバッガ(LLDB)上で取得したい場合。

頂点の数を取得する。

デバッガ
po mdlMesh.vertexCount
// 出力結果:54

バッファのデータのstrideを確認する。

デバッガ
po mdlMesh.vertexDescriptor.layouts.filter {($0 as! MDLVertexBufferLayout).stride != 0}
// 出力結果:
// ▿ 1 element
//   - 0 : <MDLVertexBufferLayout: 0x2824e4490 stride=32>

strideは32であることがわかった。

次のコードで、fromByteOffsetにオフセットを与えると頂点の情報が確認できる
n番目の要素を得たいときは、n * strideで取得できる。例えば2番目の要素を取得したいときは2*32を与える・

デバッガ
po mdlMesh.vertexBuffers.first!.map().bytes.load(fromByteOffset: 1*32, as: Float3.self)
// 出力結果:
// ▿ SIMD3<Float>(0.5, 0.5, 0.5)
//   ▿ _storage : SIMD4Storage
//     - _value : (Opaque Value)

2番目の頂点の座標は、x = 0.5, y = 0.5, z = 0.5であることがわかった。

最後に

NoteではiOS開発、とくにCoreML、ARKit、Metalなどについて定期的に発信しています。
https://note.com/tokyoyoshida

Twitterでも発信しています。
https://twitter.com/jugemjugemjugem

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

【SwiftUI】SwiftUI Appで`window.rootViewController`を用いた初期画面の表示

はじめに

アプリの初期画面をwindow.rootViewControllerを用いて表示することは採用したアーキテクチャにもよると思いますが、よくあることかと思います。
ただし、プロジェクト作成時にLife CycleSwiftUI Appを選択した場合に少し実装が必要だったため記しておきます。

実装

SwiftUI Appでプロジェクトを作成すると、以下のようなファイルが生成されます。
このままだとContentViewが初期表示画面になってしまいます。
例えばCoordinatorRooterパターン等を利用したい場合はAppDelegateSceneDelegateを経由したくなります。

SampleApp.swift
import SwiftUI

@main
struct SampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

まず、AppDelegateSceneDelegateをそれぞれ自分で作成します。
自作したSceneDelegateが呼び出されるような実装をAppDelegateにしていきます。

SceneDelegate.swift
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = SampleViewController()
            window.makeKeyAndVisible()
            self.window = window
        }
    }

}
AppDelegate.swift
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        let config = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
        config.delegateClass = SceneDelegate.self
        return config
    }

}

これであとは、AppDelegateが呼び出されるようにするだけです。
@UIApplicationDelegateAdaptorを利用します。

SampleApp.swift
import SwiftUI

@main
struct SampleApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
        }
    }
}

これで、SceneDelegateで指定しているSampleViewControllerが表示されるようになります。

おわりに

そもそもSwiftUI Appを選択しなければ良い話ですが、参考になる方がいればいいなと思います。
単純に起動時に処理がしたいだけであればScenePhaseというものもあるようです。
https://developer.apple.com/documentation/swiftui/scenephase

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

開発中のiOSアプリをiOSエンジニア以外にテストしてもらうにあたって

開発中のiOSアプリをiOSエンジニア以外にテストしてもらう際に、TestFlightやDeploygate, firebase app distributionなどの配布ツールを使って確認してもらうにあたって、iOSエンジニアが確認しておくことの備忘録

TestFlight

内部テスター

  • 内部テスターは100人まで
    • チームでAccount Holder、Admin、App Manager、Developer、Marketingのいずれかの役割を担うメンバーを最大100人まで追加
  • 追加するメールアドレスはAppleIDである必要がある
  • テスターに配布する前にApple審査はなし
  • アップロード、Appleサーバーでのビルド時間に30分〜1時間程度の時間がかかる
  • 100デバイス制限あり

外部テスター

  • 追加するメールアドレスはAppleIDである必要はなし
    • Eメールアドレスを使用するか、任意のユーザーに対してAppのテストに参加する機会を開くパブリックリンクを有効にして共有
  • 1万人までテスターを登録してアプリを配布できる
  • 100デバイス制限も関係ない
  • テスターに配布する前にApple審査が発生し、(1日程度)ビルドが承認され次第、テスト開始できる

Deploygate(or firebase app distribution

  • 追加するメールアドレスはAppleIDである必要はなし
    • Eメールアドレスorパブリックリンク,QRコードで共有
  • テスターに配布する前にApple審査なし
  • メール招待後、DeveceUDIDを登録し証明書を更新、更新後の次の配布バージョンから確認可能
    • 初回の追加時は次回配布まで待つ必要があるので時差あり、証明書の管理者に更新をおねがいする必要あり
  • 100デバイス制限あり

比較

開発物の確認開始までの時間

Deploygate > TestFlight内部テスター > TestFlight外部テスター

参加できる人数

TestFlight外部テスター > Deploygate == TestFlight内部テスター

参加への手軽さ

TestFlight外部テスター > Deploygate > TestFlight内部テスター

よくある確認フロー

開発中 Deploygate

ある程度バグがなくなって申請前に確認 TestFlight内部テスター

リリース前に確認 TestFlight外部テスター

開発途中の物を確認、テストしたい場合はDeploygateを使ってテストするのがよい。
人数制限はあるので、アプリ開発者、サーバー開発者、テスターでの確認用に使うとよい。
アプリ側でバグがあった時に修正して更新、確認してもらうなど、更新回数が多い段階で見てもらうのに使う。
Develop, Staging環境など複数環境を揃えやすいのもメリット。

大規模開発において、関わる人が多い場合はTestFlight外部テスターを使って多くの人にテストしてもらうのがよい。
テスト開始できるまでに審査が必要なので余裕を持ってテストスケジュールを組む必要がある。
テスターの参加人数の多い場合は、多くの人の時間を使ってしまうので、Deploygateである程度バグを潰した状態で見てもらうようにする。
また、アプリに詳しくない人にも確認してもらう場合は、

  • DeploygateはDevice UDIDの登録必要
  • TestFlightは内部テスターはAppleIDが必要

などの、テスト参加者に理解してもらえない用語や制約が多いため、どの段階からどのツールで見てもらうかはよく検討する必要がある。

どの段階からどのツールで見てもらうか検討例

  • リリースの品質決定権のある人
  • デザイナー
  • テスターが足りない時にモンキーテスト的にデバッグを手伝ってくれる社内の人

このあたりの役割の人はある程度早く見てもらう必要があるが、かといって、あまり早い段階で見てもらっても混乱が起きたり、有意義でなテスト時間になりにくいことがある。
よくある対応として

  • Deploygateに参加してもらいつつ、見て欲しいタイミングで声かけをして更新してもらう
  • 開発用とは別に開発後半用のDeploygateビルドを別途作成する
  • TestFlight内部テスターとして参加してもらい、TestFlightの更新をリリース前でなくある程度余裕を持ってやる

などがある。

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

HitTestを実施した際に、Containerが反応しない

問題

テスト環境でHitTestにてContainerを検出することを確認後、本番環境に実装を行った。
が、なぜかContainerがHitTestにて検出されない問題が発生した。

解決方法

Containerのcolorに透明な色を適用することで、HitTestにて検出されるようになった。

原因

Flutter.devのContainerのページにも記載があったが、colorに何もしていない場合、ContainerはHitTestにて検出されなくなってしまうみたい。

By default, containers return false for all hit tests. If the color property is specified, the hit testing is handled by ColoredBox, which always returns true. If the decoration or foregroundDecoration properties are specified, hit testing is handled by Decoration.hitTest.

https://api.flutter.dev/flutter/widgets/Container-class.html

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

【覚書】iOS アプリ Code keyboard のショートカット一覧

アプリ紹介

https://apps.apple.com/gb/app/code-keyboard/id1097372399?l=ja

コーディングに特化した iOS キーボードアプリ。
このアプリ、詳細な説明書とか一切ないのだが、一応特定のキーを押しっぱなしにすると、
コーディングで使用率の高い記号や演算子などを素早く入力できるようになっている。

この記事では、それらを一個一個検証して調べてみた。

abc モード

 q w e r t y u i o p
  a s d f g h j k l
[S] z x c v b n m [<x]
[123]?[       ][Ent]
Q W E R T Y U I O P A L Z M ?
1 2 3 4 5 6 7 8 9 0 - = && // ⚙️
! @ # $ % ^ & * ( ) + == || /*
{ } * != & */
[ ] / < |
++ > !
-- >=
<=

123 モード

  1 2 3 4 5 6 7 8 9 0
  - / : ; ( ) $ & @ "
[#+=].  ,  ?  !  ' [<x]
[abc]?[<-][ ][->][Ent]
- / $ & " . ? ! ' ?
-- \ | && .. ¿ != ` ⚙️
// || @"

#+= モード

  [ ] { } # % ^ * + =
  _ \ | ~ < > € £ ¥ •
[123].  ,  ?  !  ' [<x]
[abc]?[<-][ ][->][Ent]
% . ? ! ' ?
.. ¿ != ` ⚙️

Enter 長押し モード

  { } [ ] ( ) < > #  =
  - + * / \ | & ^ ++ --
[\t] . , ? ! ' " @ [<x]
[123]?[         ][Ent]
< > = - + / | & ! ?
<= >= == -- ++ // || && != ⚙️
  • このモードでは、タブ文字が打てる

おすすめの使い分け

  • 基本的には abc モードを使用
    • A L Z M キーで演算子を出せることを覚えておく
  • 1 ~ 2 桁程度の数字は QWERTYUIOP で入力
    • 3 桁以上入力したいときは 123 モードを使用
  • 括弧やちょっとした記号や演算子が欲しい時は Enter 長押し
    • 見つからないときは #+= モードを使用

このように、基本的には abc 123 モードを使い、
記号が欲しい時に Enter 長押し する感じで使えば、良い感じに使えそう。

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

英語が苦手な人のためのXcode便利機能 SpellCheck

はじめに

こんにちは!スーパー超絶英弱エンジニアのせーたろです!
profileをplofileと書いてしまう英語力の僕が、インターン先のつよつよエンジニアから教えてもらった便利機能を紹介します。

Spell Checkの使い方

Xcode11から導入されたSpell Checkという機能を使います。
スクリーンショット 2021-01-22 1.00.17.png

Edit < Format < Spelling and GrammarからCheck Spelling While Typingをオンにします。

これでスペルミスをしている箇所に赤い点線が表示されるようになります。
スクリーンショット 2021-01-22 1.03.54.png

修正

ダブルクリックで修正できます。
スクリーンショット 2021-01-22 1.04.21.png

ショートカットキー

command⌘ + ;でスペルミスの箇所がハイライト、
command⌘ + :でSpelling and Grammar のウィンドウが表示されます。
スクリーンショット 2021-01-22 1.06.15.png

さいごに

この便利機能のおかげで、レビューなどでスペルミスの指摘を減らすことができるのではないでしょうか!
よければ使って見てください!

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

Swift Packageのバージョンを最新に解決できない

概要

iOSアプリ開発のCI/CDを行うときは、xcode buildやfastlaneでビルドやテストを行うと思います。その際にプロジェクト(ワークスペース)が参照しているSwift Packageがなかなか狙い通りに解決されなかったため、備忘録として残します。

とりあえず結果

結論としてはxcodebuildやfastlaneのパッケージ解決の方法では難しいことがわかりました。Package.resolvedやDerivedDataを削除しても謎のファクターXを参照して、古いリビジョンを解決してしまいます。

最新リビジョンを取得するワークアラウンド

そのプロジェクトがSPMでない場合でも、Package.swiftを用意し、そこにSPMのパッケージを書きます。
で、アップデートして、Package.resolvedを移動させます。

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "Hoge",
    platforms: [
        .iOS(.v14),
    ],
    dependencies: [
        .package(name: "Hoge", url: "https://xxxxxxxxx",
        .branch("master"))
    ]
)



swift package update
mv Package.resolved Hoge.xcworkspace/xcshareddata/swiftpm/
bundle exec fastlane tests

この場合、Package.resolvedを参照してほしいので、fastlaneの場合は、disableAutomaticPackageResolutionを有効にします。

Fastfile.
    run_tests(..,
              xcargs: "-disableAutomaticPackageResolution",
              ...
              )

これで最新版をなんとか解決できました!

パッケージ解決に関与してそうなパラメータ

Package.resolved

XXX.xcodeproj/xcshareddata/swiftpm/Package.resolved というパスにあるファイルです。基本的にこのファイルがある場合は、このファイルに記載されているリビジョンのものがチェックアウトされますが、無視する設定もできるようです。

DerivedData

いわゆるビルド時の中間ファイルです。これがあると最新を取得してきてくれないことがあります。 このパスは指定することができるようで、fastlaneだとcloned_source_packages_pathというパラメータで指定することができます。xcodebuildだとclonedSourcePackagesDirPathというパラメータです。

resolvePackageDependencies

xcodebuildコマンドに渡すパラメータです。このパラメータの挙動を正確に把握していないのですが、プロジェクトAがSwiftPackageBとSwiftPackageCをxcodeprojで参照しており、SwiftPackageBがSwiftPackageCを参照していた場合、プロジェクトAが参照するプロジェクトCのバージョンは、プロジェクトBのPackage.Swiftのバージョンになる、という挙動をしました。

というところまでは調べたのですが、ファクターXがなんなのかが結局わかりませんでした。

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