【Swift】Realm で CGFloat が非推奨なことに気がついたので Float にマイグレーションした話
どうも。Reoです。
Realm を使っていたアプリ(OKAIMO)が、Xcode11.5 + iOS13.5 環境で、起動後クラッシュするようになってしまいました。
CGFloatを使っていた部分がクラッシュしてしまうので、CGFloat → Float へのマイグレーション処理を行いました。
せっかくなので記事として残しておきます。
環境
- macOS Catalina (10.15.5)
- Xcode 11.5
- Swift 5.1.3
- iOS 13.5.1
事象
Terminating app due to uncaught exception 'RLMException', reason: 'Property Color.hue is declared as CGFloat, which is not a supported managed Object property type. If it is not supposed to be a managed property, either add it to `ignoredProperties()` or do not declare it as `@objc dynamic`. See https://realm.io/docs/swift/latest/api/Classes/Object.html for more information.'
というエラーでクラッシュ。
原因
クラッシュしている原因は、Realm オブジェクトのプロパティにCGFloatを使用していることでした。
CGFloatはプラットフォーム依存で定義が変わってしまうようで、RealmのドキュメントにもCGFloatは使うなと書いてありました。
CGFloat properties are discouraged, as the type is not platform independent.
CGFloat型はプラットフォーム(CPUアーキテクチャ)によって実際の定義が変わるため、使用しないようにしてください。
[iOS]RealmのモデルクラスのプロパティにCGFloatを指定してはいけない - Qiita も参考にさせていただきました。
マイグレーション処理
CGFloat を Float にマイグレーションしていきます。
まずはプロパティを CGFloat から Float に変更します。
final class Color: Object, Codable {
// 変更前
@objc dynamic var hue: CGFloat = 0
@objc dynamic var saturation: CGFloat = 0
@objc dynamic var brightness: CGFloat = 0
@objc dynamic var alpha: CGFloat = 1
// 以下に変更
@objc dynamic var hue: Float = 0
@objc dynamic var saturation: Float = 0
@objc dynamic var brightness: Float = 0
@objc dynamic var alpha: Float = 1
// 略
}
実際に使っているところは Float(hue), CGFloat(hue) のように変換しておきます。
このまま実行すると、マイグレーションをしてねと言われるのでマイグレーション処理をします。
RealmMigration.swift というファイルを作成しました。全体は以下。
https://gist.github.com/uruly/a799e5f4cdafbe9585945d7506f93780
final class RealmMigration {} 部分はどのプロジェクトでも使えるようにしてあります。
実際のマイグレーション処理はextensionで書いた部分です。
extension RealmMigration {
private func migrationTo2(_ migration: Migration) {
migration.enumerateObjects(ofType: "Color") { old, new in
guard
let hue: CGFloat = old?["hue"] as? CGFloat,
let saturation: CGFloat = old?["saturation"] as? CGFloat,
let brightness: CGFloat = old?["brightness"] as? CGFloat,
let alpha: CGFloat = old?["alpha"] as? CGFloat else {
fatalError("Migration is Failed.")
}
new!["hue"] = Float(hue)
new!["saturation"] = Float(saturation)
new!["brightness"] = Float(brightness)
new!["alpha"] = Float(alpha)
}
}
}
単にそれぞれ古い値をFloatに変換して入れ直しています。
最後に、アプリ起動時にマイグレーション処理が走るように AppDelegate 内で呼び出します。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
RealmMigration.shared.configure()
return true
}
これで実行して無事起動することができました。
おわりに
CGFloat が非推奨なんて全然知らなかったです。普通に使えるから、使えると思ってしまうじゃんか...こんなトラップがあるなんて...
久々に触ると本当に予期せぬクラッシュが多くてビビりますね。
今回は、自分が書いたAppAppのリファクタリング記事に助けられました。この時より汎用性ある感じにはなったハズ...
それではでは。
コメントはありません。
現在コメントフォームは工事中です。