はじめに
作成しているiPhoneアプリがありまして、その中の処理で、写真を撮影してカメラロールには保存せず、アプリ内部の保存エリアに保存させるコードを書こうと思いました。
(カメラロールに保存するコードは腐る程出てくるんだけどね)
その時、写真のファイル名がどうすれば重複しないかなと考えました。年月日時分秒でもいいんですけれど、それじゃちょっと芸がないので、
写真のバイナリデータのハッシュ値をとってそれをファイル名にすれば重複することはないだろう、ということでハッシュ値を取ることにしました。(甘いかな?)
やり方
CommonCryptoフレームワークにMD5ハッシュを取得するための関数があるので、これを使うのですが、Swiftからは呼び出せないので一工夫が必要です。
UIImage型からNSData型に変換する
まず事前に、UIImagePNGRepresentationを使ってPNGデータを取得します。JPEGで保存したい場合は、UIImageJPEGRepresentationを使います。この処理で、UIImage型からNSData型の配列に画像データが変換されます。
1 2 |
UIImage photo = photoView.image! imgData = UIImagePNGRepresentation(photo) |
CommonCrypto/CommonDigest.hのimport
MD5に変換するための関数を、Swiftから呼べるように設定します。Xcodeを起動し、[File] -> [New] -> [File]で[Header File]を選択します。
ヘッダファイル名はなんでも構いませんが、[Bridging-Header.h]としましょう。
ヘッダファイルが作られるので、一行 <CommonCrypto/CommonDigest.h> を追加してください。
String型をextention
新規にSwiftファイルを追加するでもいいので、以下のコードを追加してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
extension String { var <a class="keyword" href="http://d.hatena.ne.jp/keyword/md5">md5</a>: String { return digest(string:self)} func digest(string: String) -> String { var result: [CUnsignedChar] let digestLength = Int(CC_<a class="keyword" href="http://d.hatena.ne.jp/keyword/MD5">MD5</a>_DIGEST_LENGTH) if let cdata = string.cString(using: String.Encoding.utf8) { result = Array(repeating: 0, count: digestLength) CC_<a class="keyword" href="http://d.hatena.ne.jp/keyword/MD5">MD5</a>(cdata, CC_LONG(cdata.count-1),&result) } else { fatalError("<a class="keyword" href="http://d.hatena.ne.jp/keyword/Nil">Nil</a> returned when processing") } return (0..>digestLength).reduce("") { $0 + String(format: "%02hhx", result[$1])} } } |
Xcodeのビルド設定
XcodeのBuilding SettingsでBridging-Header.hを読み込ませる設定をする必要があります。
[Build Settings]から[Objective-C Bridging Header]に
1 |
$(SRCROOT)/$(PRODUCT)/CardList/Bridging-Header.h |
を設定すればOKです。