【Swift】UITextViewのリンクをタップするとクラッシュした話

UITextView のリンクをタップ → アプリ内で画面遷移 ってのを実装したのですが、その際にリンクをタップしたらクラッシュしたことがありました。
大したエラーログも出ず、メインスレッドで呼ぶんじゃねぇの一点張り。
解決方法は単純でしたが、直接的な検索結果には出てこなかったので、残そうと思います (・ω・)

開発環境(前提条件)

・Xcode13.3
・Swift5
・リンクは NSMutableAttributedString で追加している

クラッシュの内容

UITextView のリンクをタップすると、以下のようなログが出て怒られます。

This method should not be called on the main thread as it may lead to UI unresponsiveness.

「このメソッドをメインスレッドで呼び出すと UI が反応しなくなる可能性がありまっせ」言われてます。
UITextView に対してメインスレッドで呼ぶようなコード書いたかな…と思って調べたのですが、もちろんそんなことしてなくて、マジなんなん状態で1時間ほど無駄にしました。

クラッシュの原因

NSMutableAttributedString で追加したリンクに日本語が入っていたことが原因でした。笑
リンクをローカライズで変えていたので、ぱっと見で気付かず…マジしょぼんです (-ω-)
下記のようにリンクに日本語が入っていると URL が nil になってしまいます。

let urlString = "https://google.com/search?q=日本語やん"
let url = URL(string: urlString)  // nil

// 少々脱線しますが、urlString がリンクである必要はなく、
// "日本語やん" だと nil になりますが "japanese" だと大丈夫です。

厳密に言うと、日本語が入っているというより、URLとして認識されない文字が正しいですね。
この URL を利用して UITextView にリンクが作られたために、クラッシュが起きていました。

解決方法

文字列にパーセントエンコーディングをかけることでクラッシュしなくなります。

let urlString = "https://google.com/search?q=日本語やん"
let url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))

この addingPercentEncoding(withAllowedCharacters:) を使うことで、URL で扱うことが出来ない文字をパーセント(%)と英数字で表現できるようになり、日本語が含まれているリンクでも URL で扱うことが出来ます。
ちなみにデコード処理は以下になります。

let urlString = "https://google.com/search?q=日本語やん"
let url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))

// この時点での url.absoluteString の中身は
// https://google.com/search?q=%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%84%E3%82%93

let decodeUrlString = url.absoluteString.removingPercentEncoding

// decodeUrlString の中身は https://google.com/search?q=日本語やん

以上ォ!!

さいごに

クラッシュ内容は This method should not be called on the main thread as it may lead to UI unresponsiveness. じゃなくて、URL の変換に失敗しました的なことを出してほしい _:(´ཀ`」 ∠):_

Swift
スポンサーリンク

コメント