swiftからC/ObjCを触る (例: String -> SHA256)

　Swiftを単体で弄るだけでは面白くありません。ご先祖様が残してくださったC/ObjC資産をどんどん使っていきましょう。
　ブリッジングヘッダーについて調べ始めたあたりの人を念頭に置いた記事です。参考になる記事の纏めも兼ねています。

# C => ObjC => Swift

　Swiftは書いていて愉しい言語ですが、Swiftで書かれたソースはまだまだ多くありません。しかも名前がややこしいため、簡単な処理であっても調べるのが大変です。「swift やりたいこと」で検索したらCDアルバムやクルマ、[謎の組織](http://www.swift.com/jp)あるいは[並列処理が得意な方のswift](https://jp.linux.com/news/linuxcom-exclusive/405880-lco201307023)が出てきてイラつく経験は誰しも通る道でしょう。
　そういう時には、諦めることなくC/ObjCのコードを検索してみましょう。C/ObjCで書けることはほとんどそのままSwiftで書けますし、C/ObjCで書かれたライブラリーはswiftから容易に利用できるからです。

## CommonCrypto

　タイトルにもあるように、この記事では文字列からSHA256を得ることを例に挙げます。幸いなことに、この問題については「Swift SHA256」と検索することで参考になる記事をいくつも発見できます。
　StringからSHA256その他のハッシュ値を得るには、`CommonCrypto` の持つ関数を使えば簡単です。これはSwiftの一部ではなく、[オープンソースのC言語製ライブラリー](http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-7/CommonCrypto/CommonDigest.h)です。

　ここでいきなり「アルゴリズムが分かっているのだから、swiftらしさ全開で書き直すべきだ」という人は多分いないでしょう。自在にC/ObjC資産を使いまわすほうが、遥かに「Swiftらしい」に違いありません。

　ということで、まずはブリッジングヘッダーを書きましょう。そもそも作り方が分からんという方は参考記事をご覧ください。

```Bridging-Header.h
#import <CommonCrypto/CommonDigest.h>
```

　これで準備が整います。簡単ですねー。

　ただし、Swiftで愉しく楽して簡単に使えるのはC/ObjCのヘッダーだけです。C++を使おうとすると結構な手間がかかります。

- [Objective-C, Objective-C++ のコードを Swift で使う](http://qiita.com/mokumoku/items/a228d9f3db95b16fbae9) (@mokumoku)　
- [SwiftプロジェクトでC++を使う方法メモ](http://qiita.com/hiz_/items/2108344de95c1470b104) (@hiz_)

　ちなみに、自分で用意したライブラリー (homebrewでインストールしたライブラリーとか) を使う場合には、ライブラリーをリンクしてヘッダーをインクルードするだけでなく、Xcodeにおいて Header Search Paths を通さなければいけません。インクルードすべきファイルがどこにあるか、知らせる必要があるからです。
　個人的には `/usr/local/include` をよく書き足します。

# Objective-C without the baggage of C
![f32262.png](https://qiita-image-store.s3.amazonaws.com/0/17957/2cdaac45-e26e-ed62-ba66-457fc55c029c.png)

　~~それってsmalltalk~~ 

　フェデリギお兄さん曰く、ObjCからCを取り外すとSwiftなんだそうです。ということで、Swiftにはポインタとかchar配列とかいう[古代C言語](http://ja.uncyclopedia.info/wiki/古代C言語)は出てこない… ように見えます。
　しかし、それはピュアなSwiftの世界に出てこないだけの話であって、「出せない」わけではないのです。

- [How to use CC_MD5 method in swift language](http://stackoverflow.com/questions/24123518/how-to-use-cc-md5-method-in-swift-language)

```swift
extension String {
    var md5: String {
        let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
        let strLen = CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
        
        CC_MD5(str!, strLen, result)
        
        var hash = NSMutableString()
        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }
        
        result.dealloc(digestLen)
        
        return String(format: hash as String)
    }
}
// 注：一部修正有
```

　**君なんか写真と違わない？**
　見るからにC言語っぽいですね。

　Swiftには、正常に動くC言語のロジックをほとんどそのまま持ち込むために必要な道具が揃っています。使えるものを再利用するわけですから、極めて生産的です。「なんかCっぽい」書き方もSwiftらしさと考えるべきでしょう。
　ただ、上の例はちょっと幾ら何でもC言語の風味が強すぎるような気がします。`str!` とアンラップしていることが気になりますし、メソッドなので使うときに `()` を付ける必要があるのも面倒です。

　ということで、書き直しましょう。いかにもSwiftっぽく。

```swift
extension String {
    var sha256: String! {
        if let cstr = self.cStringUsingEncoding(NSUTF8StringEncoding) {
            var chars = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
            CC_SHA256(
                cstr,
                CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)),
                &chars
            )
            return chars.map { String(format: "%02X", $0) }.reduce("", combine: +)
        }
        return nil
    }
}

// 使い方
println("Swift".sha256)
// -> AE8ED2743925477EAFAD0DFDB0D0832702634DA4DC6EC1AEFA4F3A61953E93F0
```

　オプショナル型のアンラップは`if let`で回避し、ポインターはArrayで代替し、`for`は使わずmapで済ませることができます。
　記憶力の貧弱な現代人としては、ポインターを直接触ったり、メモリ管理に手を出すのはなるべく避けたいところです。

　なお、ここでの戻り値は`String!`型にしています。これは真っ当な理由があるわけではなく、`cStringUsingEncoding(NSUTF8StringEncoding)`がどういう場合にnilを返すのか分からないので「たぶんnilが返ってくることはないだろう」と決めつけただけです。
　「絶対にnilが返ることはない」と断定できるなら、`if let`を使わずアンラップする方が単純なのですが… どうなんでしょうか。

- [Swift - UnsafePointerと上手に付き合う](http://qiita.com/dankogai/items/2d19b8352183cca3461f) (@dankogai)
- [SwiftのOptional型を極める](http://qiita.com/koher/items/c6f446bad54442a28bf4) (@koher)

　以上です。Swift/ObjC/Cの連携は記事も少なめですが、触れば案外なんとかなるので頑張ってください。

## おまけ
　最初は`if let`のかわりにmapを使って書いたんですが、やたら見た目が分かりにくいので止めました。

```swift
extension String {
    var sha256: String! {
        return self.cStringUsingEncoding(NSUTF8StringEncoding).map { cstr in
            var chars = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
            CC_SHA256(
                cstr,
                CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)),
                &chars
            )
            return chars.map { String(format: "%02X", $0) }.reduce("", combine: +)
        }
    }
}
```