LoginSignup
5
5

More than 5 years have passed since last update.

autoreleasepoolで例外を投げられるようにする

Posted at

一時的にメモリの消費が増える部分で、autoreleaseを使うのに加え、do〜try〜catchでエラーハンドリングをするといった場面があって、

autoreleasepool {
    do {
        try process()
    } catch (let e) {
        //
    }
}

こうではなくて、、、

雑多な例ですが...

func doSomeTask() {
   do {
       for i in (0..<100) {
           autoreleasepool {
               // 大きい画像を扱うので結構メモリを消費するからautoreleasepoolを使いたい
               let largeImage = UIImage(contentsOfFile: "image\(i).png")
               // 何らかの処理
                try ~~~~~~~~ //これができない!! ★
            }
       }
   } catch (let e) {
       print(e) // ★の例外をここで拾いたい
   }
}

このように使いたい場合に、autoreleasepoolが例外をthrowできないので上記のように書くことができません。
なので、上記の例ができるように、以下の用に実装してみます。

実装してみる

public func autoreleasepool(@noescape code: () throws -> ()) rethrows {
    try {
        var error: ErrorType?
        autoreleasepool {
            do {
                try code()
            } catch (let e) {
                error = e
            }
        }
        if let error = error {
            throw error
        }
    }()
}

あまり綺麗に書けないですが、予めErrorTypeが入る変数をautoreleasepoolの外に宣言し、
内部でcode()を実行し、エラーをキャッチしたら先に用意した変数にいれ、それをautoreleasepoolを抜けたあとにthrowします。

同じ関数名ですが、エラーもなく宣言ができます。
これで、先ほどの例で、autoreleasepoolの前に、tryを付けてあげることで、実現することができます。

使用してみる


func doSomeTask() {
   do {
       for i in (0..<100) {
           try autoreleasepool {
               let largeImage = UIImage(contentsOfFile: "image\(i).png")
               // 何らかの処理
                try ~~~~~~~~ // ★
            }
       }
   } catch (let e) {
       print(e) // ★の例外をここで拾うことができる!
   }
}

何故同名の関数なのに問題ないのか

autoreleasepoolオリジナルの宣言を見てみると、

定義
public func autoreleasepool(@noescape code: () -> ())

となっていて、引数の型が

() -> () (オリジナル)
() throws -> () (今回実装したもの)
となっているので違う引数の型と判断され、結果としてオーバーロードした事になります。

autoreleasepoolに渡すクロージャーの内部でtryで例外を投げる可能性がある場合は、今回実装した方のautoreleasepoolが適応され、クロージャーの内部で例外が投げられることがない、通常の使い方の場合は、オリジナルの方が適応されます。


autoreleasepool {
    // 通常の autoreleasepool
}

try autoreleasepool {
    try ~~~~~
    // 例外をthrowできるautoreleasepool
}


5
5
0

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
5
5