swift - result型で結果を返すのは邪道か,王道か

10

Click here to load reader

Upload: yuichi-yoshida

Post on 31-Jul-2015

1.057 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Swift - Result型で結果を返すのは邪道か,王道か

Objective-C厨がSwiftにハマったでござる

Programming

Yuichi YoshidaChief engineer, DENSO IT Laboratory, Inc.

#potatotips

@sonson_twit

© 2014 Yuichi Yoshida, All rights reserved. Redistribution or public display not permitted without written permission from Yuichi Yoshida.

Swift - Result<T>型で結果を返すのは邪道か,王道か

Page 2: Swift - Result型で結果を返すのは邪道か,王道か

自己紹介2tchの中の人

• iOS好きです • 2tch(2ちゃんねるビューア) • iOS SDK Hacksなど

• 研究・開発 • コンピュータビジョン • 機械学習 • 画像検索サービスとか • 車向けサービスやハードウェアとか

Page 3: Swift - Result型で結果を返すのは邪道か,王道か

reddiftSwift Reddit API Wrapper

• 1億人以上のアメリカのSNS • APIあり • Objective-CのAPI Wrapperはあり

• OAuth2に対応してない • Swiftじゃない

• よし,いっちょ,勉強がてら作るか! • MIT License

https://github.com/sonsongithub/reddift

Page 4: Swift - Result型で結果を返すのは邪道か,王道か

よくあるコード?

func linkList( paginator:Paginator?, sortingType:ListingSortType, subreddit:Subreddit?, completion:( links:[Link], paginator:Paginator?, error:NSError? )->Void) -> NSURLSessionDataTask

ダウンロード後のコールバックをブロックで渡す

Page 5: Swift - Result型で結果を返すのは邪道か,王道か

書き方もありますが func linkList(paginator:Paginator?, sortingType:ListingSortType, subreddit:Subreddit?, completion:(links:[Link], paginator:Paginator?, error:NSError?)->Void) -> NSURLSessionDataTask { var parameter:[String:String] = [:] if let paginator = paginator { if paginator.sortingType == sortingType { parameter = paginator.parameters() } } var path = sortingType.path() if let subreddit = subreddit { path = "/r/\(subreddit.display_name)\(path)" } var URLRequest = NSMutableURLRequest.mutableOAuthRequestWithBaseURL(baseURL, path:path, parameter:parameter, method:"GET", token:token) let task = URLSession.dataTaskWithRequest(URLRequest, completionHandler: { (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in self.updateRateLimitWithURLResponse(response) if error != nil { dispatch_async(dispatch_get_main_queue(), { () -> Void in completion(links:[], paginator: nil, error: error) }) } else { if let json:[String:AnyObject] = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.allZeros, error: nil) as? [String:AnyObject] { let (links, paginator) = self.parseLinkListJSON(json) if links.count > 0 && paginator != nil { paginator?.sortingType = sortingType; dispatch_async(dispatch_get_main_queue(), { () -> Void in completion(links:links, paginator:paginator, error:nil) }) } else { dispatch_async(dispatch_get_main_queue(), { () -> Void in completion(links:links, paginator:paginator, error:NSError.errorWithCode(0, userinfo: ["error":"Can not get any contents expectedly."])) }) } } else { dispatch_async(dispatch_get_main_queue(), { () -> Void in completion(links:[], paginator: nil, error:NSError.errorWithCode(0, userinfo: ["error":"Can not parse response object."])) }) } } }) task.resume() return task }

エラーと戻り値がぐちゃぐちゃに

Page 6: Swift - Result型で結果を返すのは邪道か,王道か

Functional Concepts and Generics

session?.getList(. . . . . . , completion: { (result) in switch result { case let .Error(error): println(error.code) case let .Value(box): println(box.value) // do something } })

https://robots.thoughtbot.com/efficient-json-in-swift-with-functional-concepts-and-generics

基本,ここと岸川さんの受け売り

Page 7: Swift - Result型で結果を返すのは邪道か,王道か

戻り値をResult<T>にする

public enum Result<A> { case Success(Box<A>) case Failure(NSError) public init(value:A) { self = .Success(Box(value)) } public init(error: NSError) { self = .Failure(error) } ........ }

public final class Box<A> { public let value: A public init(_ value: A) { self.value = value } }

正しい戻り値か,Errorオブジェクトのどちらかを返す

enumになる

Page 8: Swift - Result型で結果を返すのは邪道か,王道か

戻り値へのアクセスのイメージ

(a : Result<Hoge>) -> Void { switch(a) {

case let .Success(x): println(x.value)

case let .Failuare(x): println(x.error)

} }

Page 9: Swift - Result型で結果を返すのは邪道か,王道か

んで演算子定義と組み合わせると,

let task = URLSession.dataTaskWithRequest(request, completionHandler: { (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in let responseResult = resultFromOptionalError(Response(data: data, urlResponse: response), error)

let result = responseResult >>> parseResponse >>> decodeJSON

completion(result) }) task.resume()

もはや後から読めない綺麗なコードができあがる!!!

Page 10: Swift - Result型で結果を返すのは邪道か,王道か

まとめ,ではなく議論• Result<A>で書くと綺麗

• 演算子定義もやるとさらに綺麗 • 他の書き方もある

• flatMap? • 多くのOSSでみんな車輪の再発明をやってる

• 読みやすいか • 書きやすいか • デバッグしやすいか

議論したいです,ハイ