Help us understand the problem. What is going on with this article?

Swiftのデバッグが捗るデバッグ関数を独自定義する

More than 3 years have passed since last update.

Swiftのデバッグ関数をつくる

アプリ道場 Advent Calendar 2015のトップバッター、@mo_to_44です。Advent Calendarの最初の投稿なのでゆるめにデバッグ関数の定義をしてみようと思います。

DebugLog関数

こちらがコードです。コードはgistにアップしています。

func DebugLog(@autoclosure condition: () -> Bool = true, _ message: String = "", function: StaticString = __FUNCTION__, file: StaticString = __FILE__, line: UInt = __LINE__) {

    #if DEBUG
        if let fileName = NSURL(string: String(file))?.lastPathComponent {
            print("time: \(NSDate()), message: \(message), function: \(function), file: \(fileName), line: \(line)")
        } else {
            print("time: \(NSDate()), message: \(message), function: \(function), file: \(file), line: \(line)")
        }

        assert(condition, message, file: file, line: line)
    #endif

}

#if DEBUGの設定方法ですが、Build Settings > Swift Compiler > Other Swift Flagsに -DDEBUGを指定すればOKです。

スクリーンショット 2015-11-30 0.16.18.png

なにをしているのか

なにをしているのか見ていきましょう。DebugLog関数でやっていることは以下の通りです。

  1. DebugLogが呼び出された時間の出力
  2. DebugLog呼び出し元のファイル名出力
  3. DebugLog呼び出し元の関数名出力
  4. DebugLog呼び出し元のファイル内の行数出力
  5. assertの実行

1については簡単ですね。print関数内でNSDate()を呼び出して現在の時間を出力しているだけです。それ以外の部分について見ていきましょう。

関数名、ファイル名、ファイル内の行数の出力

Swiftでは__FILE__, __LINE__, __COLUMN__, __FUNCTION__という特殊な識別子が定義されており、これを利用して関数名、ファイル名、ファイル内行数の出力を行っています (参考)

__FILE__ __LINE__ __COLUMN__ __FUNCTION__
ファイル名 行数 カラム 関数

assert関数呼び出し

conditionfalseだった場合はassertが実行されるようになっています。異常な値が入っている場合にassertが実行されます。

デフォルト引数を指定してログとassertを使い分けるようにする

DebugLogの引数は全てデフォルト引数を指定しているので、DebugLog()のように呼び出した場合は単にログのみが出力されます。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        DebugLog()
    }

}

上記のコードを実行した場合、以下のログが出力されます。

time: 2015-11-29 14:55:09 +0000, message: , function: viewDidLoad(), file: ViewController.swift, line: 16

デバッグ時にassertで値のチェックもしたい場合は以下のように呼び出します。someValueが1未満の場合はログの出力とともに、assertで実行を停止します。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let someValue = 0
        DebugLog(someValue > 0)
    }

}

以下のようなログが出力され、プログラムが停止します。

time: 2015-11-29 14:58:32 +0000, message: , function: viewDidLoad(), file: ViewController.swift, line: 18
assertion failed: : file /Users/Motoki/Desktop/Example/Example/ViewController.swift, line 18

第2引数には付加情報としてメッセージを入れることができます。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let someValue = 0
        DebugLog(someValue > 0, "Unexpected value")
    }
}

このように指定した場合は、以下のように出力されます。

time: 2015-11-29 15:11:03 +0000, message: Unexpected value, function: viewDidLoad(), file: ViewController.swift, line: 16
assertion failed: Unexpected value: file /Users/Motoki/Desktop/Example/Example/ViewController.swift, line 16

まとめ

必要な情報はプロジェクトによっても変わってくると思うのですが、関数名、ファイル名、行数などが分かるとデバッグ時に便利かと思います。今回は状況によってはassert関数を実行させるようにしました。

デバッグ関数を定義する際の参考にしてみてください。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした