kumamotone’s blog

iOS/Android アプリエンジニアです https://twitter.com/kumamo_tone

Xcode 10 にして Swift 4.2 対応した

iOS12 対応やってた方々からすると今更感あるかもしれないけど、本日(日付的には昨日) Xcode 10 が正式リリースとなったので、重い腰を上げて(本業とは別でやってる)アプリの Swift 4.2 対応した。

All Fix Issues

思ったより名前が変わったンゴよというやつがあったので、めんどいなーと思いながら、そういやファイル内のぽちぽち全部自動でやってくれるやつなかったっけ?と思って調べた。

あった。Editor > All Fix Issues (ctrl+option+cmd+F) でいいっぽい。

これを使って一括でやっていった。

このメニュー、 Xcode 9 あたりではなんか一時的に無効になってた気もするのだが(気のせい?)、普通に使えた。

自動で書き変わらんかったやつ

ほとんど All Fix Issues するだけでよかったのだが、そうじゃないのももちろんあった。

UIEdgeInsetsInsetRect(rect, insets) → rect.inset(by: insets)

ググったら https://github.com/dani-gavrilov/GDPerformanceView-Swift/pull/20/files が 出てきたので参考にした。

NSNotificationName. UIDeviceOrientationDidChangeNotification → UIDevice.orientationDidChangeNotification

長い…

NSNotificationName を NSNotification.Name に変えるだけでXcodeくんが満足してしまったので、オイオイ待ていとなって、

うーんどうしようかなと思ったのだけど、 1回前半を削って「UIDeviceOrientationDidChangeNotification」にしてみたら正しいのをサジェストしてくれるようになった。

このアプリ画面回転することは無くなったので、結局これは死にコードなのだが…

New Build System

リネーム以前にとりあえずプロジェクト開いたときにビルドを拒否られた。

:-1: The new build system doesn’t yet support On Demand Resources; if you require ODR, the legacy build system can be reenabled in File > Workspace/Project Settings…. (in target 'xxxxxx')

言われるがままに File > Project Settings (WorkSpace Settingsの場合もあるかも)から「Legacy Build System」にしたら一応通った。

ググったけど全然情報が出ない アタイも New Build System とやらを使ってみたいよ

(追記)ODRはリソースが必要になったときに追加ダウンロードするようにできる仕組み。使ってないけどなぜかONになってた。Build Settings > Assets の Enable On-Demand Resources を切ればいいっぽい(参考: App Thinning メモ

f:id:kumamotone:20181012001034p:plain

へーってなったやつ

  • bringSubview(toFront: titleLabel) → bringSubviewToFront(titleLabel)

  • sendSubview(toBack: mainColorView) → sendSubviewToBack(mainColorView)

これ昔に戻ったって感じなんかな? どっちでもいいけど

toggle()

これでコンパイルは通るようになったが、 Swift 4.2 の機能を先取りして生やしとるもんがあったなと思ったので掃除した。

その1。

extension Bool {
    @_inlineable
    public mutating func toggle() {
        self = !self
    }
}

Swift 4.2 のプロポーザル見てこれええやんってなって入れてたやつ、役目を終えたので消した。

extension Int {
    @inlinable
    public mutating func toggle() {
        if self == 1 {
            self = 0
        } else if self == 0 {
            self = 1
        }
    }
}

派生してこんなもんも生やしていた。

こんなもんを使わんといかん状態がまずダメじゃね?っていう話もあるのだが、これは消すとコンパイル通らんのでひとまず残した。

CaseIterable

その2。

人のを参考に EnumEnumerable という名前で生やしていた。

protocol EnumEnumerable {
    associatedtype Case = Self
}

extension EnumEnumerable where Case: Hashable {
    private static var iterator: AnyIterator<Case> {
        var n = 0
        return AnyIterator {
            defer { n += 1 }
            
            let next = withUnsafePointer(to: &n) {
                UnsafeRawPointer($0).assumingMemoryBound(to: Case.self).pointee
            }
            return next.hashValue == n ? next : nil
        }
    }
    
    static func enumerate() -> EnumeratedSequence<AnySequence<Case>> {
        return AnySequence(self.iterator).enumerated()
    }
    
    static var cases: [Case] {
        return Array(self.iterator)
    }
    
    static var count: Int {
        return self.cases.count
    }
}

結構使っているところが多く cases を allCases という名前にするのがめんどくさかった。 cases という比較的何かしらに混ざってそうな名前を一括で置換するのは若干こわいので、目視で確認しながらやってた。

しかし、やり終わってから気づいたが、予め Xcode のリネーム機能で EnumEnumerable の cases を allCases にしておけば、EnumEnumerable を CaseTerable に置換するだけで良かったんじゃねともおもった。

そんなに規模の大きいアプリでなかったのでこの程度ですみました。おわり