Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
iOS18でQRコードが表示されなくなった🤷
Search
Ryomm
December 06, 2024
Programming
0
88
iOS18でQRコードが表示されなくなった🤷
2024.12.06 KTC×WED×フェンリル 3社合同イベント
Ryomm
December 06, 2024
Tweet
Share
More Decks by Ryomm
See All by Ryomm
iOSでQRコード生成奮闘記
ktcryomm
2
230
リョムキャットのパーフェクトSwiftネーミング教室
ktcryomm
0
2k
Slackを使いこなせ!Slack効率3000倍
ktcryomm
0
980
クソアプリ作って煙突詰めた♪
ktcryomm
0
59
Other Decks in Programming
See All in Programming
The Evolution of Enterprise Java with Jakarta EE 11 and Beyond
ivargrimstad
1
840
Haskell でアルゴリズムを抽象化する / 関数型言語で競技プログラミング
naoya
17
4.8k
Bytecode Manipulation 으로 생산성 높이기
bigstark
2
360
第9回 情シス転職ミートアップ 株式会社IVRy(アイブリー)の紹介
ivry_presentationmaterials
1
200
Using AI Tools Around Software Development
inouehi
0
1.2k
都市をデータで見るってこういうこと PLATEAU属性情報入門
nokonoko1203
1
550
エンジニア向け採用ピッチ資料
inusan
0
140
コード書くの好きな人向けAIコーディング活用tips #orestudy
77web
3
330
Effect の双対、Coeffect
yukikurage
5
1.4k
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
120
今ならAmazon ECSのサービス間通信をどう選ぶか / Selection of ECS Interservice Communication 2025
tkikuc
11
2.8k
プロダクト開発でも使おう 関数のオーバーロード
yoiwamoto
0
160
Featured
See All Featured
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Unsuck your backbone
ammeep
671
58k
The Straight Up "How To Draw Better" Workshop
denniskardys
233
140k
Bash Introduction
62gerente
614
210k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Raft: Consensus for Rubyists
vanstee
140
7k
Mobile First: as difficult as doing things right
swwweet
223
9.7k
Making Projects Easy
brettharned
116
6.3k
For a Future-Friendly Web
brad_frost
179
9.8k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Transcript
None
None
None
None
調査の結果、どうやらこちらのコードでnilが返ってきているっぽい
このコードでは何をしているかというと、こちらの名前の通り…
文字列として渡されたバイナリからQRコードを作っています
ここで、QRコードの仕様について補足、、 QRコードに格納ができるデータはこちらの4種類です。 この中で、8ビットバイトモードを使うとバイナリを格納することが可能です。 バイナリを入れられるということは、日本語以外でもどんな文字列でも入れられるということです。
my routeでは文字列として受け取ったバイナリを16進数バイナリとしてQRコードで読み取れるようにする処理があります。 先ほどのコードでは、このへんで変換を行なっています。
わかりやすさのため、具体的にみていきます。 先ほどのコードを分解するとこのようになっています。
文字列として謎のバイナリXを受け取って、それを16進数バイナリ、つまりData型に変換します。
例えば謎のバイナリXを 6e79dc68 とします。
普通にutf8でData型にすると、元の値がただの文字列として扱われてしまいます。 Data型にした時に、受け取った文字列がカンマが取れるようにしたいので、コネコネします。
まずは文字列を16を基数として変換し、数字として扱えるようにします。 ここではBigNumberというライブラリを使って変換していますが、標準のIntでも似たようなことができます。10進数にすると 1853480040 となりました。 BIntというのは、8バイトの整数を格納できる型です。ここでは普通の整数だと思ってもらって大丈夫です。
続いて、UInt8の配列に変換します。 先ほどのBigNumberライブラリを使うと簡単に取得することができます。 ライブラリ上ではBytesという表記ですが、これはtypealiasで[UInt8]となっています UInt8とは2進数で8ビットまで格納できる型で、一個前の10進数を2進数に変換し、お尻から8桁ずつ切り取って配列にしたものです。頭の足りない分は0で埋めています。
そして、UInt8の配列をData型にするため、文字列とエンコード方式のセットを取得したいです。 そのため、エンコード方式を把握した状態で一旦String型に変換します。
最後に、先ほどエンコードした方法で、今度は文字列をData型にエンコードします
これで、受け取った文字列をData型に変換することができるようになりました! 値が同じままダブルクォートが取れていることがわかります
そう、iOS17までは…
iOS18において、UInt8の配列をStringに変換しようとしたとき、nilが返ってくるようになってしまいました!
Swift6の大きな変更のひとつに、Foundationの実装移行があります。 FoundationにはAppleプラットフォーム向けのと、LinuxなどApple以外のプラットフォーム向けのものがあります。 Swift5では、どちらもCoreFoundationというC言語で作られた内部実装に深く依存しています。 ただ、これはObjCとの親和性が高い実装なので、Swiftで実装し直されました
それが、swift-foundationです。 Swift6のタイミングで、この内部実装が切り替わりました。
そして、iOSにおいて、FoundationはOS内蔵のものが使われていると言われています つまり、iOS18になったタイミングでiOS18に内蔵されたFoundationの参照先がswift-foundationになったことで、iOS18でロジックが壊れる影響が出たと考えられます。 では、Foundationが変わったことで、Stringのinitでどんな差分が発生しているのか詳しく見てみます。 (discordでIcemanさんに教えてもらいました)
問題のコードではUTF-16BEでデコードしています。 UTF-16は0000からFFFFまで全部使う規格なので、基本的にサロゲートペア以外でデコードには失敗しません。 サロゲートペアとは、、 UTF-16においては基本的に2バイトで文字を表現しますが、それだと65535個の文字しか表現できないため、さらに拡張するために編み出されたものです。 D800〜DBFFの上位サロゲートと、DC00〜DFFFの下位サロゲートを組み合わせて表現します。 で、先ほどのUTF-16BEでデコードしようとしていた値を見てみます。 2つ目のdc68が下位サロゲートのコード範囲にあたっています! しかし、ペアとなる上位サロゲートがないためデコードは失敗します (discordでomochimetalさんに教えてもらいました)
前は何かしらの値を無理矢理返却していましたが、新しいfoundationではデコードに失敗した時にnilが返ってくるように仕様が変わっていたのです。
(回想) 100%再現するわけじゃない、という現象の理由は、 たまたまデコードできた時にはQRコードが表示されていたってことか…
変換処理を修正しようと思います。 まず、謎のバイナリXは、なにでエンコードされたものかわかりません。 なので、なんでもいいから一旦デコードして、Stringとそのエンコード方式のペアを取得したいです。
そう、、なんでもいいから一旦デコードしたい…!
名付けて総当たり大作戦!! なんでもいいから一旦デコードできるものを探します!!
ゲットしたStringとエンコード方式を使ってData型に変換します! やったー!変換に成功した!
None
なんか…違和感がある…
…これいる? [UInt8]からData型の変換もっとシンプルにできないの? 総当たりで探し回って一旦String型に変換するのって変じゃない??
[UInt8]からDataへ変換する他の方法を探していると、このような記載を発見しました
None
[UInt8]からStringへの変換処理、全然いらんかったー!
超シンプルにData(byte)でよかった
うわあああこれをQRコード生成メソッドに組み込んで完成!
foundationの内部実装の切り替えの煽りを受けた結果、遠回りした実装になってたことがわかったはなしでした〜
QRコードのデータのモードを判別するにはモード指示子を解読する必要があります。 そしてそれを解読する前にQRコードのマスクパターンを取得します。今回は000なので、こちらの計算式が得られました。
取得したマスクパターンとモード指示子の4ビットの排他論理和を取得します。 これは0100なので、8ビットバイトモードだ!とわかりました