LoginSignup
218
167

More than 3 years have passed since last update.

Swift の guard は正しく使いましょう

Last updated at Posted at 2016-04-26

概要

guardの使い方を整理していた時にhttp://radex.io/swift/guard/ の記事を見つけてしまったので超訳しつつリビルドしてみました。

はじめに

Swiftのguard構文はエラーが発生したら終了この値は来てほしくない,などのguard節として利用と、アンラップした変数を以降の処理でも使いたい などの場面で使われるのが一般的かと思います。

実際の案件でのコードレビューを見てみると、ifで良い場面でguardを使ったり、guardを使うことで逆にわかりにくくなったりするケースがありました。リファレンスに書かれている使い方をもう一度明確にするために利用方法を整理してみます。

一般的な使い方

アンラップした変数をスコープ外で利用する

変数をアンラップしてguardブロック以降のスコープでも利用する

guard let url = NSURL(string: coverPath) else { // NSURL.init?(string URLString: String)
    abort()
}

if imageManager.cachedImageExistsForURL(url) { 
    省略...

早期リターンとしての利用

メソッド開始直後に条件を満たしていなければ早期にリターンする

private func deleteDownloadTask() {
    guard let realm = self.realm() else {
        return
    }

    try! realm.write {
    // realmを使ったなんらかの処理
    }
}

複数条件の判定

カンマで区切って複数条件をチェックしつつアンラップできます。
長い処理の中での中断を判定する処理としてもguardは有効利用できます。

※Xcode12からは面倒だった複数行のインテントが揃うようになったとのことです

func onUpdateSubscriptionLevel(notification: NSNotification) {
    if self.isTopmost(true) {
        guard let channel = self.viewModel.channel,
              let episodes = self.viewModel.episodes else {
            return
        }

        // 何らかの処理

        guard let subscribe = notification.parameter().data as? Subscribe else {
            return
        }

        // 何らかの処理
    }
}

アサーションとしての利用

※単純なチェックならassertでもいいと思います。

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    guard let story = self.viewModel.stories?[indexPath.row] else {
        abort()
    }

    // 何らかの処理
}

NGな使い方

どちらかを返すようなメソッドの中で利用する

func isLogin() -> Bool {
    guard let _ =  SettingService.sharedInstance.currentUserId else {
        return false
    }
    return true
}

// 判定結果を返せばいいので != で良い。 

func isLogin() -> Bool {
    return SettingService.sharedInstance.currentUserId != nil
}

Rubyのunlessの様に利用する

Rubyには条件式が偽の場合の処理を記述する「unless」という構文があります。

Swiftのguardは名前の通りguard節としての利用方法が正しい使い方ですので、unlessのように使うと可読性が悪くなります。

// 悪い例
guard SettingService.sharedInstance.isUserLogined(userId) == true else {
    // ユーザーIDをセットする処理
}

// 改善例
// guard 構文内にロジックを書くのは分かりにくいので if を利用する
if !SettingService.sharedInstance.isUserLogined(userId) {
    // ユーザーIDをセットする処理
}

まとめ

guardはアンラップ 兼 guard節として利用しましょう

参考

Swift_Programming_Language Statements

218
167
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
218
167