しおメモ

雑多な技術系ブログです。ニッチな内容が多いです。

iOS

XCTestを使ったflaky testの扱い方

Xcode13からXCTest周りの機能が強化され、特にflaky testに対応しやすくなったので、実際の対応方法をいくつか書きます。 Flaky testの再現確認 XCTSkipを利用してskipする XCTExpectedFailureを利用して結果を成功扱いにする 動画リンク Flaky testの再現確…

ARCによるオブジェクトの破棄タイミングをずらす

Swiftの場合、特に意識せずとも各オブジェクトに対してARCによるメモリ管理が行われ、コンパイル時にreference countのincrement/decrementの処理(retain/release)が挿入されます。 ほとんどの場合、retain cycleを避けることなどのわずかなことを意識してお…

CADisplayLinkを用いたアニメーション実装

iOS

複雑なアニメーションを実装する場合に、画面の更新(垂直同期)に合わせて、アニメーションの更新処理をしたいケースがあります。 単純にTimerなどで実装した場合、アニメーションの処理が呼ばれるタイミングが画面の更新と合わないため、次の垂直同期までに…

Cellに直接addSubviewするコードに警告を出す

ちょっと前のアップデートで、正しくcontentViewに追加していない場合に、セルの挙動がおかしくなるケースが多発したと思います。 この前Xcode13に上げたタイミングでも食らってしまい、 cellに直接addSubviewしたいケースも多分ないと思ったので、作ってみ…

Property wrapperを使ってCodableの一部のプロパティをencodeしないようにする

最近リファクタをしていて、同じオブジェクトを使ってencodeとdecodeをする際に、必要なケースがでてきたので書きました。 状況 Property wrapperを使った解決 Equatableへの応用 サンプルコード 状況 以下のHogeのように一部のパラメーターでdecodeはしたい…

よくある実装でDateComponentsFormatterやRelativeDateTimeFormatterを使う

DateFormatterに関しては古くからあり、おおよそのプロジェクトで使われているイメージですが、DateComponentsFormatterやRelativeDateTimeFormatter(iOS13+なので最近)については体感としてあまり使われておらず、特に歴史のあるプロジェクトでは独自のform…

potatotips #74に参加して発表しました

6月23日(水)にPotatotips #74に参加させていただき、iOS枠で発表しました。 potatotips.connpass.com ちょうどWWDCの後だったこともあり、SharePlayやGroup Activitiesなど、自分がキャッチアップできていない部分のお話を聞けて、とても楽しかったです。 An…

LLDB経由でPythonを利用してStringの示すURLを開く

iOS開発をしていてデバッグする際に、コピーしたり、"を外したりするのが地味にめんどくさいので作ってみました。 今回は、SwiftのStringをopenurl hogeのようなコマンドで開くのを目指します。(Swift以外でもほぼ同じです) openurlコマンドの作成 コマンド…

OSLogを利用したロギング

iOS開発でログを利用する場合、自前のロガーを利用したり、OSSを利用する選択肢が多いですが、標準のOSLogのAPIが新しくなり、iOS14以降で使いやすくなりそうなので、紹介します。 printと比べて何が良いか OSLogを利用した出力 Loggerを用意する ログを出力…

SwiftにおけるBastard Injectionとは

結構ありがちな書き方なので、書いてみました。 Bastard Injectionとは なぜBastard Injectionが問題となるのか なぜ書いてしまうのか 置き換える方法 見るべき動画 Bastard Injectionとは Bastard Injection(Poor Man's Dependency Injection)は、他の言語…

iOSのキーボードの高さと連動したビューを作る

絶対忘れる自信があるので書いておきます。 なんとなく、この辺りのインターフェースもまた変わりそうな予感がするので、暫定Swift 5、iOS 13版です。 NotificationCenter(raw) NotificationCenterはライフサイクルに合わせてobserverを破棄してくれるので、…

iOSアプリの圧縮済みAssets内の画像のサイズを調べて小さくする

せっかくインストールしたアプリを削除されたくないので、インストール後のバイナリサイズを削ってみました。 今年は細かい作業やりたくないので、忘れないうちに記録に残しておくことにしました。 まず見るWWDCのセッション アプリのサイズ Assetsの中でか…

LLDBからRxSwiftのdebugを仕込む

毎回ソースコードいじってRxSwiftのdebug仕込むのってめんどいですよね。 そこで、スクリプトを使ってLLDBから仕込めるようにしました。 流れてくるイベントを簡単にチェックするのに役に立つかもしれません。

Xcodeのビルド時間をキレずに改善する

Xcode10でNew Build Systemになってから、全体的にビルド時間は短くなりました。 しかし、それでも諸々の原因によりビルドがめちゃくちゃ遅い場合があります。 そんな場合でも、キレずに冷静に改善する方法紹介します。 ビルド時間の計測方法 ビルド設定の見…

RxSwiftのSchedulerの実装を読んだ

少し前に、RxSwift5のSchedulerの実装を読んでみたので、初めての読んだ系記事です。 概要 observeOnとsubscribeOn Serial/Concurrent Scheduler 主な組み込みのスケジューラー MainScheduler ConcurrentMainScheduler SerialDispatchQueueScheduler Concurr…

XcodeのLLDBデバッグでよく使う技

若干話題になって出尽くしてる感がありますが、XcodeのLLDBを絡めたデバッグでよく使う手法をまとめてみました。 特定の行をスキップ 特定の行を書き換える ブレークポイントをon/offする アドレスからオブジェクトに戻して変数に格納する 組み込みメソッド…

Swiftのメソッドごとのコンパイル時間を表示するワンライナー

忙しい人向けに、.xcactivitylogからメソッドのコンパイル時間を抽出するワンライナーです。 gunzip -c -S .xcactivitylog hoge.xcactivitylog | perl -pe "s/\r/\n/g" | grep -E "^\d+\.\d+ms" | sort -nr | uniq | head -100 中身はただのgzipですが、\rが…

NimbleのPredicateの自作方法とサンプル

Nimbleでテストを書いていた際に、共通部分を`Predicate`として自作してまとめたいことがあったので、実装の方法と簡単なサンプルを記しておきます。

UIView.animateをメソッドチェーンで書く

UIView.animateは引数が多く、animationとcompletionで2つクロージャーを引数に取り、ネストも深くなりやすいため、メソッドチェーンで書けるように改良してみました。 サンプル 実装 AnimationBuilder AnimationExecutor アニメーション開始用のstaticメソ…

ターミナルでXcodeのデバッグログを見れるようにした

前にファイル出力できるロガーをつくっていたので、ターミナルで見やすいようにちょこっと改良してみました。 Xcodeのウィンドウでは色がつけられなくなってしまったので、出てきたものにPerlで色を付けています(ゴリ押し)。

Swiftのassert系メソッドとfatalErrorの使い方

Swiftには、assertと似た役割を持つメソッドとして、preconditionやfatalErrorがあります。 これらのメソッドの使い方について考えてみます。

今さらUIPageViewController詳解

UIPageViewControllerが登場したのが古いこともあり、公式ドキュメントや、ネットに出ているの情報だと、いまいち各メソッドの挙動までは掴みづらかったので、改めてまとめてみました。

Arrayのextensionでサブクラスにダウンキャスト

タイトル通りで、UIViewControllerやUIViewのArrayから特定のサブクラスだけ抜き出す処理はよく書くので、 ただのaliasですが、少しでも楽しようとextensionにしてみる。 extension Array { func `as`<E>(_ type: E.Type) -> [E] { return self.compactMap({ $0</e>…

Swiftで作成したiOS向けframeworkをローカライズする

普通のアプリの場合は、NSLocalizedStringにキーを渡すだけで大丈夫なのですが、frameworkを公開する場合、デフォルトだとアプリ側のBundleを参照してしまうので、そちらも正しく指定しなくてはいけません。 情報が少なかったので、その方法を記載しておきま…

Swift4で範囲の文字列表現をRangeに落とし込む

正確には、RangeExpressionのような、containsで要素を含むかどうかを判定できる適当なクラスに落とし込みます。 今回はRange(0.0...1.0みたいなやつ)だけではなく、RangeExpressionに適合するのすべてのクラスに対応したいと思います。 Swift4.2からRange系…

DispatchQueueによる非同期処理を見直す

他言語から入ると、一見取っつきづらいDispatchQueueですが、だいぶ浸透してきた気がします。 一方で、簡単にマルチスレッドで非同期処理ができるようになった結果、処理フローの制御がしづらくなったり、 知らないうちに、CPUやメモリリソースを異常に消費…

SwiftのARCとクロージャのキャプチャ

Swiftのバージョンが上がる前に、クロージャーに対して各種方法で変数をキャプチャした際の挙動を整理します。 ちなみに、新卒アドベントカレンダーではないです。 ARCについての前提知識 強参照と弱参照の違い 強参照 弱参照 キャプチャの種類 組み込み型の…

Swift用デバッグロガー Linna

一ヶ月ほど前から、ちまちま開発を進めていた、 Swift用のデバッグロガー"Linna"の紹介です。 日本語ドキュメントはこちらです。 github.com 特徴 ロードマップ 特徴 JavaやJavascriptなど、他言語の代表的なロガーの機能を踏襲しつつ、 出来るだけシンプル…

SwiftでRustのようなResult型を実装する

Swiftで従来のthrow~catchでは書きづらい場面も多々あるので、 RustのResult型を参考にした、エラーハンドルを取り入れてみました。 やること 実装 case メソッド その他 使い方 switchで使う Optionalで使う サンプル やること SwiftでRustのResult型のよう…

Obj-Cライブラリ由来のNSExceptionのSwiftでのハンドリング

ずばりこれ。 NSSetUncaughtExceptionHandler(_:) - Foundation | Apple Developer Documentation swiftのcatchで拾えないものもこちらでハンドルできる。 AppDelegate等に入れておく。 func application(_ application: UIApplication, didFinishLaunchingW…