PointTown iOSアプリをObjective-CからSwift化した時のTips集
Swift iOS

PointTown iOSアプリをObjective-CからSwift化した時のTips集

このエントリーをはてなブックマークに追加

ICON

こんにちは!iOS大好きだけど最近はAndroid開発ばかりして欲求不満な玉澤です。

皆さんSwift書いてますか?

今回は、PointTownアプリをObjective-CからSwiftに移行するときに役だった簡単なTipsをご紹介します。

Objective-CからSwift化するときのゆるいポリシー

PointTownアプリをデザインリニューアルをするタイミングで、Swiftに置き換えていったため、以下の3点を意識して取り組みました。

  • Swift化が目的出はないので、100%Swift化を目指さない。
  • Swiftで追加された言語仕様を積極的に使って楽をする。(guard, let, struct, for in whereなど)
  • 得られた知見を共有していく。(社内勉強会やブログとかで)

NSKeyedArchiver+NSUserDefaultでキャッシュしてるオブジェクトの扱い

Swift化したとしても、既存ユーザーの端末にキャッシュされているオブジェクトはObjective-Cから作られたものなので、Swift化した際にオブジェクトに復元出来ずハマりました。 これでは、Swift化する前のアプリを使ってるユーザーに影響が出てしまいます。 そういう時は@objc(クラス名)を定義して解決することが出来ます。

@objc(UserInfo) // ←これを記述することでObjective-Cで保存されていたデータをSwiftのオブジェクトで復元できる
class UserInfo : NSObject, NSCoding {

NSLayoutAnchorやUIStackViewを使う

PointTownはDeployment Targetが9.0なので、最新の技術を導入しやすかったです。

UIStackViewはAndroidでいうLinearLayoutと同じものでビューのフレーム位置を気にせずサブビューを追加出来ます。

NSLayoutAnchorはAutoLayoutをより直感的でかつ今までより高い可読性で記述出来るクラスです。

iOS8を切り捨てられない場合は、OAStackViewというバックポートライブラリを使うと良いです。

デリゲートメソッドはextensionでまとめる

Objective-Cの時は、#pragma mark – でメソッドをグループ化していましたが、 Swiftの場合extensionで分けることで、可読性があがったような気がします。 UITableViewとかは、デリゲートメソッドが多いので尚更です。

この他にも良いやり方があれば是非知りたいです。

class WebViewController : UIViewController {

}

extension WebViewController : WKUIDelegate, WKNavigationDelegate {

}

プロパティの値監視をしたい場合、willSet, didSetを活用する

プロパティ定義とまとめて定義できるので、影響範囲が狭くコードが読みやすいです。

// フラグに応じてプログレスの表示/非表示を制御
var userName:String! {
    willSet {
        // 値が変更される直前の処理を記述
        // newValueで新しい値が取れる
    }
    didSet {
        // 値が変更された後の処理を記述
        // oldValueで古い値が取れる
    }
}

※あるオブジェクトのプロパティを監視したい場合は、KVOなど使いましょう。 (self.webView.scrollView.contentSize)

データをまとまりで返したい時はStructを使う

struct APIError {
    var code:APIErrorCode
    var message:String
    var url:String
}

let apiError = APIError(code: code, message: errorMessage, url: errorUrl)

deallocはswiftだとdeinit

複数のビューと参照し合ってる場合、画面から離れた時にdeinitが呼ばれてるかブレークポイントを追加して確認しておきましょう。 メモリリークを防ぐことが出来ます。 deinitが呼ばれていないということは、どこかで強参照されているからです。 もちろんObjective-Cでもチェックしましょう。

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

Objective-CからSwiftクラスを参照したい場合

pchファイルに一行追加しておけば、すべてのクラスで参照可能になります。

#import "[ターゲット名]-Swift.h"

Objective-Cから呼ばれるSwiftクラスのメソッドの注意点

内部でPrivateメソッドを呼んでいる場合には@objcを追加しましょう

// MARK: @objcがないとUnrecognized Selectorになるので注意
@objc private static func   closeSoftKeyboard(gesture:UIGestureRecognizer) {
    gesture.view?.endEditing(true)
}

本番リリースする前にNSLog,Printによるデバッグ情報が出力されないようにしましょう。

以外と見えてはいけない情報が出てたりします。。。

func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
        Swift.print(items[0], separator:separator, terminator: terminator)
    #endif
}

func NSLog(message:String){
    #if DEBUG
        Foundation.NSLog(message)
    #endif
}

func NSLog(format:String, _ args:CVarArgType...){
    #if DEBUG
        Foundation.NSLog(String(format: format, arguments: args))
    #endif
}

Swiftで定数を複数指定する時にパイプ(|)は使えない

ビルド出来なくて、あれっと思ってしまうので覚えておきましょう。

let settings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: nil)

最後に

如何でしたでしょうか。1つでも得られたものがあれば幸いです。 Swiftをどんどん書いてSwiftライフを満喫しましょう! 今後も社内Swift化を推進していき、Swiftエンジニアを増やしていきます!! それではまた!


名無しのエンジニア
コーデスナップのiOSアプリにTodayExtensionと3D touch クイックアクションを導入した効果について
SFSafariViewControllerを導入してみました