mtc: hallo welt – restful services per restkit ansprechen
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.TRANSCRIPT
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