Swiftの機能概念とジェネリックを使用した効率的なJSON

これは、Tony DiPasquale のSwiftの効率的なJSONの機能概念の翻訳です。



翻訳者の序文



タスクは私のために設定されました: Flickr.comからJSON形式でデータをアップロードし、現時点で写真がモデルの配列に撮影された上位100の場所について:



//------   Places struct Places { var places : [Place] } //----- Place struct Place { let placeURL: NSURL let timeZone: String let photoCount : Int let content : String }
      
      





純粋に実用的なタスクに加えて、 Swiftで「型推論」がどのように機能するか、関数型プログラミングにおけるSwiftの機能を確認したかったので、Tony DiPasquale 記事「Efficient JSON in Swift with Functional Concepts」およびジェネリック ' '、ジェネリックResult : UITableViewController .



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"




















Result : UITableViewController .



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"




















拡張しResult : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















 Result       :               UITableViewController
      
      



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"
















Result : UITableViewController



.



, Swift " " Objective-C , Flickr.com Flickr API, "Stanford CS 193P iOS 7" , Objective-C .

:



extension Place: JSONDecodable { static func create(placeURL: String)(timeZone: String)(photoCount: String)(content: String) -> Place { return Place(placeURL: toURL(placeURL), timeZone: timeZone, photoCount: photoCount.toInt() ?? 0, content: content) } static func decode(json: JSON) -> Place? { return _JSONParse(json) >>> { d in Place.create <^> d <| "place_url" <*> d <| "timezone" <*> d <| "photo_count" <*> d <| "_content" } } } extension Places: JSONDecodable { static func create(places: [Place]) -> Places { return Places(places: places) } static func decode(json: JSON) -> Places? { return _JSONParse(json) >>> { d in Places.create <^> d <| "places" <| "place" } } }





... :



class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //--------------- URL places Flickr.com ------------------------------------------ let urlPlaces = NSURLRequest( URL: FlickrFetcher.URLforTopPlaces()) performRequest(urlPlaces ) { (places: Result<Places>) in println("\(stringResult(places))") } } }







"" Swift Objective-C - EfficientJSONBrief-Bridging-Header.h , FlickrFetcher.h



API Flickr



:







Github .





Apple , Swift , iOS OS X. , Xcode 6 Beta1, Swift , , JSON - - Objective-C . Swift , , , . , Swift , , , runtime . , , , . API JSON, ( Generics ) .



User

, - , , JSON. NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)



, Optional



JSON ( error ), . JSON Objective-C - NSDictionary



,



. Swift , , , . JSON Dictionary<String, AnyObject>



. AnyObject



- , JSON String, Double, Bool, Array, Dictionary



null



. JSON , , JSON , . User



:



struct User { let id: Int let name: String let email: String }







, :



func getUser(request: NSURLRequest, callback: (User) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in var jsonErrorOptional: NSError? let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) if let json = jsonOptional as? Dictionary<String, AnyObject> { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(user) } } } } } task.resume() }







if-let



, - User



. , , . , , : . , , API, .

, JSON typealias



.



typealias JSON = AnyObject typealias JSONDictionary = Dictionary<String, JSON> typealias JSONArray = Array<JSON>







:

-, .



, Either<A, B>



. , , . Swift Either<A, B>



:



enum Either<A, B> { case Left(A) case Right(B) }







Either<NSError, User>



, callback



, , "" User



, ( error



).



func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Left(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Left(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Right(user)) return } } } } // "" - , callback callback(.Left(NSError())) } task.resume() }







, getUser



switch



Either



, - User



.



getUser(request) { either in switch either { case let .Left(error): // case let .Right(user): // - user } }







, , Left



NSError



. , Result , , , . :



enum Result<A> { case Error(NSError) case Value(A) }








Swift (1.1), Result . Swift , . (constant class



) generic A



.



( . Swift enum



generic , , , generic, "" class box



):



final class Box<A> { let value: A init(_ value: A) { self.value = value } } enum Result<A> { case Error(NSError) case Value(Box<A>) }







Either



Result



, :



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional as? JSONDictionary { if let id = json["id"] as AnyObject? as? Int { if let name = json["name"] as AnyObject? as? String { if let email = json["email"] as AnyObject? as? String { let user = User(id: id, name: name, email: email) callback(.Value(Box(user))) return } } } } // "" - , callback callback(.Error(NSError())) } task.resume() } getUser(request) { result in switch result { case let .Error(error): // case let .Value(boxedUser): let user = boxedUser.value // - user } }







. .



:

JSON JSON . String, Int



Dictionary



, 3 .



func JSONString(object: JSON?) -> String? { return object as? String } func JSONInt(object: JSON?) -> Int? { return object as? Int } func JSONObject(object: JSON?) -> JSONDictionary? { return object as? JSONDictionary }







JSON :



if let json = JSONObject(jsonOptional) { if let id = JSONInt(json["id"]) { if let name = JSONString(json["name"]) { if let email = JSONString(json["email"]) { let user = User(id: id, name: name, email: email) } } } }







if-let



. , , "" .



-, Maybe



, Optional



Swift . bind



(""), , Optionals



, "" Optional



c , -Optional



Optional



. Optional



, , - .None



, .None



, bind



"" Optional



.



infix operator >>> { associativity left precedence 150 } func >>><A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None } }







>>=



bind



(""); Swift , >>>



.



JSON , :



if let json = jsonOptional >>> JSONObject { if let id = json["id"] >>> JSONInt { if let name = json["name"] >>> JSONString { if let email = json["email"] >>> JSONString { let user = User(id: id, name: name, email: email) } } } }







Optional



:



func JSONString(object: JSON) -> String? { return object as? String } func JSONInt(object: JSON) -> Int? { return object as? Int } func JSONObject(object: JSON) -> JSONDictionary? { return object as? JSONDictionary }







fmap



, . apply



, . , "" - Optional



. , Optional



, -Optional



. .Some



, , Optional



. - .None



, .None



. Swift :



infix operator <^> { associativity left } // Functor's fmap (usually <$>) infix operator <*> { associativity left } // Applicative's apply func <^><A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None } } func <*><A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a { if let fx = f { return fx(x) } } return .None }







, , ( init



) User



, Swift (auto-currying). , , , . User



:



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } }







, JSON :



if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString }







- .None



, user .None



. , .

getUser



:



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in // , callback if let err = error { callback(.Error(err)) return } var jsonErrorOptional: NSError? let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) // JSON, callback if let err = jsonErrorOptional { callback(.Error(err)) return } if let json = jsonOptional >>> JSONObject { let user = User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString if let u = user { callback(.Value(Box(u))) return } } // "" - , callback callback(.Error(NSError())) } task.resume() }







: returns "bind" ()

, callback



. return



, NSError



. bug , 3 : , JSON JSON User



.

. bind



Result



.



parseResponse



Result



data



. API iOS NSURLResponse



data



, :



struct Response { let data: NSData let statusCode: Int = 500 init(data: NSData, urlResponse: NSURLResponse) { self.data = data if let httpResponse = urlResponse as? NSHTTPURLResponse { statusCode = httpResponse.statusCode } } }







parseResponse



Response



, data



.



func parseResponse(response: Response) -> Result<NSData> { let successRange = 200..<300 if !contains(successRange, response.statusCode) { return .Error(NSError()) // } return .Value(Box(response.data)) }







Optional



Result



, .



func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> { if let a = optional { return .Value(Box(a)) } else { return .Error(error) } }







- data



JSON:



func decodeJSON(data: NSData) -> Result<JSON> { let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional) return resultFromOptional(jsonOptional, NSError()) // NSJSONSerialization }







JSON :



struct User { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> Result<User> { let user = JSONObject(json) >>> { dict in User.create <^> dict["id"] >>> JSONInt <*> dict["name"] >>> JSONString <*> dict["email"] >>> JSONString } return resultFromOptional(user, NSError()) // } }







, >>>



Result



:



func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> { switch a { case let .Value(x): return f(x.value) case let .Error(error): return .Error(error) } }







Result



:



enum Result<A> { case Error(NSError) case Value(Box<A>) init(_ error: NSError?, _ value: A) { if let err = error { self = .Error(err) } else { self = .Value(Box(value)) } } }







>>>



.



func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) let result = responseResult >>> parseResponse >>> decodeJSON >>> User.decode callback(result) } task.resume() }







, . : “ . !”, - !



: "" generics

, , JSON. generics, .

JSONDecodable



, :



protocol JSONDecodable { class func decode(json: JSON) -> Self? }







, , JSONDecodable



, Result



:



func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> { return resultFromOptional(A.decode(json), NSError()) // custom error }







User



:



struct User: JSONDecodable { let id: Int let name: String let email: String static func create(id: Int)(name: String)(email: String) -> User { return User(id: id, name: name, email: email) } static func decode(json: JSON) -> User? { return JSONObject(json) >>> { d in User.create <^> json["id"] >>> JSONInt <*> json["name"] >>> JSONString <*> json["email"] >>> JSONString } }







decode



User



, Optional User



Result. , resultFromOptional



decode



, decode



.

, performRequest



. : performRequest



parseResult



:



func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) { let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in callback(parseResult(data, urlResponse, error)) } task.resume() } func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> { let responseResult = Result(error, Response(data: data, urlResponse: urlResponse)) return responseResult >>> parseResponse >>> decodeJSON >>> decodeObject }











GitHub .



- , , Haskell Learn You a Haskell. Pat Brisbin options .





GitHub . , , , , , .



Tony DiPasquale , :



"Real World JSON Parsing with Swift" - " JSON Swift"

"Parsing Embedded JSON and Arrays in Swift" - " JSON (Arrays) Swift."



- ( ) :



"Swift e Tony DiPasquale “ JSON Swift”"



"Swift Tony DiPasquale “ JSON Swift”"



"Swift “ JSON (Arrays) Swift.”"



















All Articles