MTC: Hallo Welt – RESTful Services per RestKit ansprechen

  • View
    968

  • Download
    0

  • Category

    Mobile

Preview:

DESCRIPTION

Ein großer Teil der iOS Apps heutzutage kommuniziert auf die ein oder andere Weise mit der Aussenwelt. Eine weit verbreitete Möglichkeit dazu bieten RESTful Services. Doch wie bringe ich meiner App bei REST zu sprechen? Die Lösung heisst RestKit. Diese Session vermittelt die Grundlagen zur Anbindung von REST Services sowie die damit verbundenen Techniken, wie das Mapping auf ein Objekt-Modell und Routing von REST Ressourcen auf bestehende Klassen. Zusätzlich wird auf die Unterstützung von Core Data eingegangen, um die geladenen Daten zu persistieren.

Citation preview

Hallo Welt - RESTful Services per RestkitMichael Kotten | open knowledge GmbH @michaelkotten

@_openKnowledge

MTC2014 RESTful Services per RestKit

Webservices sind überall

MTC2014 RESTful Services per RestKit

Twitter JSON Beispiel

{ "id": 501673189681135616, "created_at": "Tue Aug 19 10:13:03 +0000 2014", "in_reply_to_screen_name": null, "in_reply_to_status_id": null, "in_reply_to_user_id": null, "retweet_count": 0, "retweeted": false, "text": "#Swift available for everybody now.", "user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten", "created_at": "Wed Sep 30 20:28:36 +0000 2009", "followers_count": 13, "friends_count": 29, "statuses_count": 27 } }

MTC2014 RESTful Services per RestKit

Twitter JSON Beispiel

{ "id": 501673189681135616, "created_at": "Tue Aug 19 10:13:03 +0000 2014", "in_reply_to_screen_name": null, "in_reply_to_status_id": null, "in_reply_to_user_id": null, "retweet_count": 0, "retweeted": false, "text": "#Swift available for everybody now.", "user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten", "created_at": "Wed Sep 30 20:28:36 +0000 2009", "followers_count": 13, "friends_count": 29, "statuses_count": 27 } }

Follow me

MTC2014 RESTful Services per RestKit

Achtung, BETA!

MTC2014 RESTful Services per RestKit

RESTful Services per NSUrlSession

var sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration() sessionConfig.HTTPAdditionalHeaders = ["Accept" : "application/json"] !var session = NSURLSession(configuration: sessionConfig) !var task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) in var json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil) as? Dictionary<String, AnyObject> var tweet = json[„text“] ... }) task.resume()

MTC2014 RESTful Services per RestKit

RESTful Services richtig

Aber wie denn jetzt?

MTC2014 RESTful Services per RestKit

RestKit

MTC2014 RESTful Services per RestKit

– RestKit.org

„RestKit is a RESTful Object Mapping Framework for iOS and OSX.“

Was ist das?

MTC2014 RESTful Services per RestKit

Warum

RestKit

?

RESTful Services per RestKitMTC2014

Features

Easy switching environments

Core Data support

A simple, high level Network layerObject Mapping

Pluggable parsing layer

RESTful Services per RestKitMTC2014

Installation per CocoaPods

‣ CocoaPods installieren 1. gem  install  cocoapods  2. pod  setup

‣ PodFile erzeugen platform  :ios,  '7.1'      pod  'RestKit',  '~>    0.23.2'  !$  pod  install  $  open  MyProject.xcworkspace

MTC2014 RESTful Services per RestKit

Objective-C importieren

MTC2014 RESTful Services per RestKit

Objective-C importieren

YES, please!

MTC2014 RESTful Services per RestKit

MyRestKitApp-Bridging-Header.h

// // Use this file to import your target's public headers that // you would like to expose to Swift. // #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import <RestKit/RestKit.h> #import <RestKit/CoreData.h>

MTC2014 RESTful Services per RestKit

Setup

let baseUrl = NSURL(string: "https://twitter.com") !// Initialize RestKit let objectManager = RKObjectManager(baseURL: baseUrl)

MTC2014 RESTful Services per RestKit

Network Indicator

AFNetworkActivityIndicatorManager.sharedManager().enabled = true

MTC2014 RESTful Services per RestKit

Object Mapping

Object Mapping

MTC2014 RESTful Services per RestKit

– RestKit.org

„Object mapping is the process of taking a representation of data in one form and

transforming it into another“

Object Mapping

RESTful Services per RestKitMTC2014

Object Mapping - Features

‣Mapping per Key-Value Coding ‣ automatische Transformation in Ziel-Typ ‣ erweiterbar

‣ Relationship-Mapping ‣ to-one und to-many ‣ Rekursiv

RESTful Services per RestKitMTC2014

Object Mapping

‣ RKObjectMapping ‣ Definiert die „Regeln“ für ein Mapping ‣ Property Mappings für Attribute und

Beziehungen

MTC2014 RESTful Services per RestKit

Object Mapping

"user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" }

class User : NSObject { var userId: NSNumber? var name: String? var screenName: String? }

MTC2014 RESTful Services per RestKit

Object Mapping

"user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" }

class User : NSObject { var userId: NSNumber? var name: String? var screenName: String? }

MTC2014 RESTful Services per RestKit

Object Mapping

"user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" }

class User : NSObject { var userId: NSNumber? var name: String? var screenName: String? }

var userMapping = RKObjectMapping(forClass: User.self) userMapping.addAttributeMappingsFromDictionary([ "id" : "userId", "name" : "name", "screen_name" : "screenName"])

MTC2014 RESTful Services per RestKit

Object Mapping

"user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" }

class User : NSObject { var userId: NSNumber? var name: String? var screenName: String? }

var userMapping = RKObjectMapping(forClass: User.self) userMapping.addAttributeMappingsFromDictionary([ "id" : "userId", "name" : "name", "screen_name" : "screenName"])

MTC2014 RESTful Services per RestKit

Swift und RestKit

Mapping Klassen müssen von NSObject

ableiten!

MTC2014 RESTful Services per RestKit

Object Mapping

class Tweet : NSObject { var tweetId: NSNumber? var createdAt: NSDate? var text: String? var inReplyToScreenName: String? var user: User? }

{ "id": 501673189681135616, "created_at": "Tue Aug 19 10:13:03 +0000 2014", "in_reply_to_screen_name": null, "text": "#Swift available for everybody now.“, "user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" } }

MTC2014 RESTful Services per RestKit

Object Mapping

class Tweet : NSObject { var tweetId: NSNumber? var createdAt: NSDate? var text: String? var inReplyToScreenName: String? var user: User? }

{ "id": 501673189681135616, "created_at": "Tue Aug 19 10:13:03 +0000 2014", "in_reply_to_screen_name": null, "text": "#Swift available for everybody now.“, "user": { "id": 78700609, "name": "Michael Kotten", "screen_name": "michaelkotten" } }

?

MTC2014 RESTful Services per RestKit

Object Mapping

let tweetMapping = RKObjectMapping(forClass: Tweet.self) tweetMapping.addAttributeMappingsFromDictionary([ "id" : "tweetId", "created_at" : "createdAt", "text" : "text", "in_reply_to_screen_name" : "inReplyToScreenName"]) !let relationshipMapping = RKRelationshipMapping(fromKeyPath: "user", toKeyPath: "user", withMapping: userMapping) !tweetMapping.addPropertyMapping(relationshipMapping)

RESTful Services per RestKitMTC2014

Response Descriptor

‣ RKResponseDescriptor ‣ Object Mapping ‣ URL Pattern ‣ Key Path ‣ HTTP Status Codes

MTC2014 RESTful Services per RestKit

Response Descriptor

let responseDescriptor = RKResponseDescriptor( mapping: tweetMapping, method: RKRequestMethod.GET, pathPattern: "/status/user_timeline/:username", keyPath: nil, statusCodes: RKStatusCodeIndexSetForClass( UInt(RKStatusCodeClassSuccessful))) !objectManager.addResponseDescriptor(responseDescriptor)

MTC2014 RESTful Services per RestKit

GETting Objects

objectManager.getObjectsAtPath( "/status/user_timeline/michaelkotten", parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in self.tweets = mappingResult.array() as [Tweet] println("\(self.tweets.count) tweets loaded") self.tableView.reloadData() }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("Error loading tweets: \(error)") })

RESTful Services per RestKitMTC2014

GETting Objects

‣ GET Request per RKObjectRequestOperation

‣ Response verarbeiten per RKResponseMapperOperation ‣ Content-Type bestimmen ‣ application/json -> NSJSONSerialization

‣ RKResponseDescriptor finden ‣ URL Pattern ‣ Key Path ‣ Status Codes

RESTful Services per RestKitMTC2014

GETting Objects

‣Mapping ausführen per RKMappingOperation ‣ valueForKeyPath("text") ‣ Transformation für NSDate etc. ‣ setValue("#Swift available for every…", forKeyPath: "text")

!

‣ Ergebnis als RKMappingResult ‣ Enthält Mapping Objekte

MTC2014 RESTful Services per RestKit

GETting Objects

„That‘s the way, we like it!“

MTC2014 RESTful Services per RestKit

Persistierung

‣ POST, PATCH/PUT und DELETE ‣ Inverse Mapping ‣ RKRequestDescriptor

MTC2014 RESTful Services per RestKit

Persistierung

var inverseMapping = tweetMapping.inverseMapping() var requestDescriptor = RKRequestDescriptor( mapping: inverseMapping, objectClass: Tweet.self, rootKeyPath: "status", method: RKRequestMethod.POST) objectManager.addRequestDescriptor(requestDescriptor)

MTC2014 RESTful Services per RestKit

POSTing Objects

var tweet = Tweet() tweet.text = "This tweet was posted using #RestKit!" objectManager.postObject( tweet, path: "statuses/update.json", parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) in println("tweet successfully posted") }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) in println("tweet post failed!") })

RESTful Services per RestKitMTC2014

POSTing Objects

‣ POST Request per RKObjectRequestOperation ‣ erzeugt NSURLRequest für URL

‣ passenden RKRequestDescriptor finden ‣ inverse Mapping

‣ Transformation nach NSDictionary !

‣ Ergebnis wieder als RKMappingResult

RESTful Services per RestKitMTC2014

PUT, PATCH und DELETE

‣ Übrige CRUD Operation analog: ‣ objectManager.putObject(…) ‣ objectManager.patchObject(…) ‣ objectManager.deleteObject(…)

RESTful Services per RestKitMTC2014

Routing

‣ Zentrale Erzeugung von Urls ‣minimiert Verwendung von Path Patterns ‣ Drei Typen von RKRoute ‣ Named Routes ‣ Class Routes ‣ Relationship Routes

MTC2014 RESTful Services per RestKit

Named Routes

objectManager.router.routeSet.addRoute( RKRoute(name: "myTimeline", pathPattern: "/status/user_timeline/michaelkotten", method: RKRequestMethod.GET) )

MTC2014 RESTful Services per RestKit

Named Routes

objectManager.router.routeSet.addRoute( RKRoute(name: "myTimeline", pathPattern: "/status/user_timeline/michaelkotten", method: RKRequestMethod.GET) )

objectManager.getObjectsAtPathForRouteNamed("myTimeline", object: nil, parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in self.tweets = mappingResult.array() as [Tweet] println("\(self.tweets.count) tweets loaded") self.tableView.reloadData() }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("Error loading tweets: \(error)") })

MTC2014 RESTful Services per RestKit

objectManager.router.routeSet.addRoute( RKRoute(class: Tweet.self, pathPattern: "/statuses/update.json", method: RKRequestMethod.POST))

Class Routes

MTC2014 RESTful Services per RestKit

objectManager.router.routeSet.addRoute( RKRoute(class: Tweet.self, pathPattern: "/statuses/update.json", method: RKRequestMethod.POST))

Class Routes

let tweet = Tweet() tweet.text = "This tweet was posted using #RestKit!" objectManager.postObject(user, path: nil, parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in println("tweet successfully posted") }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("tweet post failed!") })

MTC2014 RESTful Services per RestKit

objectManager.router.routeSet.addRoute( RKRoute(class: Tweet.self, pathPattern: "/statuses/update.json", method: RKRequestMethod.POST))

Class Routes

let tweet = Tweet() tweet.text = "This tweet was posted using #RestKit!" objectManager.postObject(user, path: nil, parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in println("tweet successfully posted") }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("tweet post failed!") })

MTC2014 RESTful Services per RestKit

objectManager.router.routeSet.addRoute( RKRoute(`class`: Tweet.self, pathPattern: "/statuses/update.json", method: RKRequestMethod.POST))

Class Routes

let tweet = Tweet() tweet.text = "This tweet was posted using #RestKit!" objectManager.postObject(user, path: nil, parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in println("tweet successfully posted") }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("tweet post failed!") })

MTC2014 RESTful Services per RestKit

Relationship Routes

var responseDescriptor = RKResponseDescriptor( mapping: userMapping, method: RKRequestMethod.GET, pathPattern: "/status/:tweetId/retweeted_by", keyPath: nil, statusCodes: NSIndexSet(index: 200)) objectManager.addResponseDescriptor(responseDescriptor) !objectManager.router.routeSet.addRoute( RKRoute(relationshipName: „retweeted_by", objectClass: Tweet.self, pathPattern: "/status/:tweetId/retweeted_by", method: RKRequestMethod.GET))

MTC2014 RESTful Services per RestKit

Relationship Routes

var responseDescriptor = RKResponseDescriptor( mapping: userMapping, method: RKRequestMethod.GET, pathPattern: "/status/:tweetId/retweeted_by", keyPath: nil, statusCodes: NSIndexSet(index: 200)) objectManager.addResponseDescriptor(responseDescriptor) !objectManager.router.routeSet.addRoute( RKRoute(relationshipName: „retweeted_by", objectClass: Tweet.self, pathPattern: "/status/:tweetId/retweeted_by", method: RKRequestMethod.GET))

var tweet = Tweet() tweet.tweetId = 4711 objectManager.getObjectsAtPathForRelationship("retweeted_by", ofObject: tweet, parameters: nil, success: { (operation: RKObjectRequestOperation!, mappingResult: RKMappingResult!) -> () in var users = mappingResult.array() as [User] println("\(users.count) retweets loaded") }, failure: { (operation: RKObjectRequestOperation!, error: NSError!) -> () in println("Error loading retweets: \(error)") })

MTC2014 RESTful Services per RestKit

Core Data

MTC2014 RESTful Services per RestKit

Managed Object Store

Core Data

MTC2014 RESTful Services per RestKit

Managed Object Store

var objectManager = RKObjectManager(baseURL: baseUrl) !let managedObjectStore = RKManagedObjectStore( persistentStoreCoordinator: persistentStoreCoordinator) objectManager.managedObjectStore = managedObjectStore

MTC2014 RESTful Services per RestKit

Mapping ändern

Core Data

MTC2014 RESTful Services per RestKit

Mapping ändern

class User : NSObject { var userId: NSNumber? var name: String? var screenName: String? }

MTC2014 RESTful Services per RestKit

Mapping ändern

@objc(User) class User : NSManagedObject { @NSManaged var userId: NSNumber? @NSManaged var name: String? @NSManaged var screenName: String?

MTC2014 RESTful Services per RestKit

Mapping ändern

@objc(User) class User : NSManagedObject { @NSManaged var userId: NSNumber? @NSManaged var name: String? @NSManaged var screenName: String? }

MTC2014 RESTful Services per RestKit

Mapping ändern

@objc(User) class User : NSManagedObject { @NSManaged var userId: NSNumber? @NSManaged var name: String? @NSManaged var screenName: String? }

MTC2014 RESTful Services per RestKit

Mapping ändern

@objc(User) class User : NSManagedObject { @NSManaged var userId: NSNumber? @NSManaged var name: String? @NSManaged var screenName: String? }

MTC2014 RESTful Services per RestKit

Mapping ändern

var userMapping = RKObjectMapping(forClass: User.self) userMapping.addAttributeMappingsFromDictionary([ "id" : "userId", "name" : "name", "screen_name" : "screenName"])

MTC2014 RESTful Services per RestKit

Mapping ändern

var userMapping = RKObjectMapping(forClass: User.self) userMapping.addAttributeMappingsFromDictionary([ "id" : "userId", "name" : "name", "screen_name" : "screenName"])

var userMapping = RKEntityMapping(forEntityForName: "User", inManagedObjectStore: managedObjectStore) userMapping.identificationAttributes = ["userId"] userMapping.addAttributeMappingsFromDictionary([ "id" : "userId", "name" : "name", "screen_name" : "screenName"])

MTC2014 RESTful Services per RestKit

Core Data Model

Core Data

MTC2014 RESTful Services per RestKit

Core Data Model

MTC2014 RESTful Services per RestKit

Managed Object Context

Core Data

MTC2014 RESTful Services per RestKit

Managed Object Context

managedObjectStore.createManagedObjectContexts()

MTC2014 RESTful Services per RestKit

Objekte erzeugen

Core Data

MTC2014 RESTful Services per RestKit

Objekte erzeugen

let managedObjectContext = objectManager.managedObjectStore.mainQueueManagedObjectContext !var description = NSEntityDescription.entityForName(„Tweet", inManagedObjectContext:managedObjectContext) !var tweet = Tweet(entity: description, insertIntoManagedObjectContext: managedObjectContext)

MTC2014 RESTful Services per RestKit

Fazit

Abspann

Lohnt sich das denn?

RESTful Services per RestKitMTC2014

Fazit

‣ Bietet viele Features ‣ Relativ einfache API ‣ Aktive Entwicklung & Community ‣ Für einfache Webservices oversized ‣ Abhängigkeit muss abgewogen werden

MTC2014 RESTful Services per RestKit

https://github.com/RestKit/RestKit

Get it now!

Hallo Welt - RESTful Services per RestkitMichael Kotten | open knowledge GmbH @michaelkotten

@_openKnowledge

Recommended