Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

2,507 views

Published on

Swift - Result<t>型で結果を返すのは邪道か,王道か
#potatotips 17での発表内容です.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Swift - Result&lt;t>型で結果を返すのは邪道か,王道か

  1. 1. Objective-C厨がSwiftにハマったでござる Programming Yuichi Yoshida Chief engineer, DENSO IT Laboratory, Inc. #potatotips @sonson_twit © 2014YuichiYoshida, All rights reserved. Redistribution or public display not permitted without written permission from YuichiYoshida. Swift - Result<T>型で結果を返すのは邪道か,王道か
  2. 2. 自己紹介 2tchの中の人 • iOS好きです • 2tch(2ちゃんねるビューア) • iOS SDK Hacksなど • 研究・開発 • コンピュータビジョン • 機械学習 • 画像検索サービスとか • 車向けサービスやハードウェアとか
  3. 3. reddift Swift Reddit API Wrapper • 1億人以上のアメリカのSNS • APIあり • Objective-CのAPI Wrapperはあり • OAuth2に対応してない • Swiftじゃない • よし,いっちょ,勉強がてら作るか! • MIT License https://github.com/sonsongithub/reddift
  4. 4. よくあるコード? func linkList( paginator:Paginator?, sortingType:ListingSortType, subreddit:Subreddit?, completion:( links:[Link], paginator:Paginator?, error:NSError? )->Void) -> NSURLSessionDataTask ダウンロード後のコールバックをブロックで渡す
  5. 5. 書き方もありますが 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 } エラーと戻り値がぐちゃぐちゃに
  6. 6. 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 基本,ここと岸川さんの受け売り
  7. 7. 戻り値を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になる
  8. 8. 戻り値へのアクセスのイメージ (a : Result<Hoge>) -> Void { switch(a) { case let .Success(x): println(x.value) case let .Failuare(x): println(x.error) } }
  9. 9. んで演算子定義と組み合わせると, 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() もはや後から読めない綺麗なコードができあがる!!!
  10. 10. まとめ,ではなく議論 • Result<A>で書くと綺麗 • 演算子定義もやるとさらに綺麗 • 他の書き方もある • flatMap? • 多くのOSSでみんな車輪の再発明をやってる • 読みやすいか • 書きやすいか • デバッグしやすいか 議論したいです,ハイ

×