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.”"


Source: https://habr.com/ru/post/J244821/


All Articles