-
-
Save non117/5676d1fcf3bab869d1af269098f00df1 to your computer and use it in GitHub Desktop.
| // | |
| // OCRClient.swift | |
| // ReceiptManager | |
| // | |
| // Created by non on 2016/10/10. | |
| // Copyright © 2016年 non. All rights reserved. | |
| // | |
| import Foundation | |
| import Alamofire | |
| public class OCRClient { | |
| let HOST = "https://vision.googleapis.com" | |
| let ANNOTATE_API = "/v1/images:annotate" | |
| var api_key: String | |
| init(api_key: String){ | |
| self.api_key = api_key | |
| } | |
| // MARK: - main request method | |
| func annotate(image: Data) -> AnnotatedResponse? { | |
| let parameters: Parameters = [ | |
| "requests": [ | |
| "image": [ | |
| "content": image.base64EncodedString() | |
| ], | |
| "features": [ | |
| [ | |
| "type": "TEXT_DETECTION", | |
| "maxResults": 2 | |
| ] | |
| ] | |
| ] | |
| ] | |
| let url = HOST + ANNOTATE_API + "?key=" + api_key | |
| var annotatedResonse: AnnotatedResponse? | |
| Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseJSON { | |
| response in | |
| print(response) | |
| if let json = response.result.value { | |
| annotatedResonse = try? AnnotatedResponse.decodeValue(json) | |
| } | |
| } | |
| return annotatedResonse | |
| } | |
| // MARK: - convenience request | |
| func annotate(imagePath: URL) -> AnnotatedResponse? { | |
| let image = try! Data.init(contentsOf: imagePath) | |
| return annotate(image: image) | |
| } | |
| } |
var annotatedResonse: AnnotatedResponse? を消したら動いた……。
まず L15 の var は let で書けると思う。
そもそも文字列結合で URL を作るのは悪手なので URL の便利メソッドを使った方がいい。 NSURL でググれば有用な情報出てきそうだし、 Swift Standard Library の URL の項目を読むのでも良い。
Alamofire の使い方が分からないのでなんとも言えないんだけど、これは多分非同期で実行されるので annotatedResonse は nil のまま即座に return されて、その後通信が成功してレスポンスがなんやかんやしたあとにクロージャの中が実行されると思う。
あとどうでもいいけど L51 の
Data.init(contentsOf: imagePath)
だけど Swift は明示的に init って書かない感じが流行りなので
Data(contentsOf: imagePath)
の方が見栄えが言いと思う。
あと OCRClient はこれだけなら class である必要はなくて struct で書いて良さそう。Swift における class と struct は C 言語とかその他の言語のそれらとは概念が全然違っていて、値型か参照型かの違いくらいしかなくて、滅多なこと(Objective-C に依存する場合とか)が無い限り値型の struct で書いて Copy on Write とコンパイラの最適化に任せた方が速い。
なんか重箱の隅ばっかだけどスネークケースな api_key より apiKey の方が Swift 感ある。
それから
let HOST = "https://vision.googleapis.com"
let ANNOTATE_API = "/v1/images:annotate"
はこの書き方だとインスタンスに紐付く定数なんだけど、意味的にはもっと大域でも良さそうなのでクラスに紐付くように
static let HOST = "https://vision.googleapis.com"
static let ANNOTATE_API = "/v1/images:annotate"
って書いた方が伝わる感じがする
Alamofire の使い方が分からないのでなんとも言えないんだけど、これは多分非同期で実行されるので annotatedResonse は nil のまま即座に return されて、その後通信が成功してレスポンスがなんやかんやしたあとにクロージャの中が実行されると思う。
なるほど!!!!
まだ重箱なんだけど
func annotate(image: Data) -> AnnotatedResponse?
の image って変数名、そのままだと UIImage とか NSImage の型かな?みたいになって混乱するから imageData みたいな名前の方が好まれそうな気はする。
文化ぜんぜん知らんので重箱の隅助かる
このくらいの規模なら Alamofire はライブラリとして超ファットに思えるので APIKit を使うのがお洒落感あるし、そもそも Alamofire も APIKit も Apple が提供してる Foundation の NSURLSession (Swift 3 では URLSession) の厚いラッパと薄いラッパなのと、URLSession の使い方は簡単なので無理に外部のライブラリに依存することはない気もする。
APIKit は NSURLSession を Swift の型の世界観に上手くお洒落に合わせるように薄く作られたイケてるライブラリという感じと言った方が良いか。
Alamofire は前身が AFNetworking ってライブラリなんだけど、とにかく全部入りを目指してる(ただし NSURLSession がそもそも全部入り)ライブラリで、AFNetworking は昔オプションの指定をアレして脆弱性を作り込んでしまった過去とかもある。
ので最近は全部入りな通信回りを任せるライブラリを使うのはやめようみたいな風潮があるというか、そもそも NSURLSession で全部出来るじゃんということに皆が気付き始めたという感じ。
AFNetworking は昔オプションの指定をアレして脆弱性を作り込んでしまった過去とかもある。
厳しい。。。
この程度の規模のAPIなら題材としても楽だし、今コスト払って公式ライブラリ使えるようになっていたほうが良さそうだね。
NSURLSession の簡単な話をすると、NSURL を放り込むと色々と OS がキューイングとか QoS とかややこしいことを肩代わりしてレスポンスを返してくれるよ、ってやつで、 iOS では 7 以降から、 macOS では 10.9 以降から使えるようになったもの。
それまで古代人達は NSURLRequest ってやつを使って、それに NSURL を放り込んでた。
NSURLSession になってややこしいことを割と OS 側に投げられるようになってみんなハッピーになったという過去がある。
んで、 NSURLSession や NSURLRequest は別に HTTP に限定されてなくて、バイナリとかも放り投げられるしソケット通信も出来る(はず、あまり使わないから忘れた)。
現代人は概ね HTTPS による通信で安全にテキストをやり取りするだろうから、古代人のようにバイナリをソケット通信で投げ合うなんて野蛮なことはしないので、NSURLSession の中の http や ssl に関する一部の機能が上手く使えれば良い、という気持ちでドキュメントを読むとすんなり理解出来そうな気はする
ネットワークライブラリ使わずに自作ネットワークライブラリつくって自分で脆弱性つくり込むより、メンテナンスされたライブラリ使った方がいいとも思いますけどね
39-45行目が実行されていない様子