SlideShare a Scribd company logo
1 of 23
Download to read offline
Mantle

https://github.com/github/Mantle

Dominik Gruber, @the_dom	

Cocoaheads Vienna – Aug. 8, 2013
Agenda
•
•
•
•

Context	

Core Data	

Alternatives to Core Data	

Mantle

Dominik Gruber	

@the_dom
Core Data
•
•

Obvious choice	


•
•

Well-documented	

It works	


But...	


•
•
•

It’s slow	

No direct SQL queries 	

A lot of boilerplate
Dominik Gruber	

@the_dom
Why is Core Data
SO slow?
•
•
•

No mass update/delete	

Synchronization between NSManagedObjectContext	
  
No transactions

Dominik Gruber	

@the_dom
Alternatives
•
•

Raw SQLite	


•
•

libsqlite3.dylib	

FMDB	


NSCoder	


•

Mantle

Dominik Gruber	

@the_dom
NSCoder
“(...) the interface used by concrete subclasses to
transfer objects and other Objective-C data
items between memory and some other format.
This capability provides the basis for archiving
and distribution.”

Dominik Gruber	

@the_dom
typedef	
  enum	
  :	
  NSUInteger	
  {	
  
	
  	
  	
  	
  GHIssueStateOpen,	
  
	
  	
  	
  	
  GHIssueStateClosed	
  
}	
  GHIssueState;	
  

!
@interface	
  GHIssue	
  :	
  NSObject	
  <NSCoding,	
  NSCopying>	
  

!
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSURL	
  *URL;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSURL	
  *HTMLURL;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSNumber	
  *number;	
  
@property	
  (nonatomic,	
  assign,	
  readonly)	
  GHIssueState	
  state;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSString	
  *reporterLogin;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSDate	
  *updatedAt;	
  
@property	
  (nonatomic,	
  strong,	
  readonly)	
  GHUser	
  *assignee;	
  

!
@property	
  (nonatomic,	
  copy)	
  NSString	
  *title;	
  
@property	
  (nonatomic,	
  copy)	
  NSString	
  *body;	
  

!
-­‐	
  (id)initWithDictionary:(NSDictionary	
  *)dictionary;	
  

!
@end

Dominik Gruber	

@the_dom
-­‐	
  (id)initWithDictionary:(NSDictionary	
  *)dictionary	
  {	
  
	
  	
  	
  	
  self	
  =	
  [self	
  init];	
  
	
  	
  	
  	
  if	
  (self	
  ==	
  nil)	
  return	
  nil;	
  

!
	
  	
  	
  	
  _URL	
  =	
  [NSURL	
  URLWithString:dictionary[@"url"]];	
  
	
  	
  	
  	
  _HTMLURL	
  =	
  [NSURL	
  URLWithString:dictionary[@"html_url"]];	
  
	
  	
  	
  	
  _number	
  =	
  dictionary[@"number"];	
  

!
	
  	
  	
  	
  if	
  ([dictionary[@"state"]	
  isEqualToString:@"open"])	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  _state	
  =	
  GHIssueStateOpen;	
  
	
  	
  	
  	
  }	
  else	
  if	
  ([dictionary[@"state"]	
  isEqualToString:@"closed"])	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  _state	
  =	
  GHIssueStateClosed;	
  
	
  	
  	
  	
  }	
  

!
	
  	
  	
  	
  _title	
  =	
  [dictionary[@"title"]	
  copy];	
  
	
  	
  	
  	
  _body	
  =	
  [dictionary[@"body"]	
  copy];	
  
	
  	
  	
  	
  _reporterLogin	
  =	
  [dictionary[@"user"][@"login"]	
  copy];	
  
	
  	
  	
  	
  _assignee	
  =	
  [[GHUser	
  alloc]	
  
initWithDictionary:dictionary[@"assignee"]];	
  

!
	
  	
  	
  	
  _updatedAt	
  =	
  [self.class.dateFormatter	
  
dateFromString:dictionary[@"updated_at"]];	
  

!
	
  	
  	
  	
  return	
  self;	
  
Dominik Gruber	

@the_dom
-­‐	
  (id)initWithCoder:(NSCoder	
  *)coder	
  {	
  
	
  	
  	
  	
  self	
  =	
  [self	
  init];	
  
	
  	
  	
  	
  if	
  (self	
  ==	
  nil)	
  return	
  nil;	
  
!
	
  	
  	
  	
  _URL	
  =	
  [coder	
  decodeObjectForKey:@"URL"];	
  
	
  	
  	
  	
  _HTMLURL	
  =	
  [coder	
  decodeObjectForKey:@"HTMLURL"];	
  
	
  	
  	
  	
  _number	
  =	
  [coder	
  decodeObjectForKey:@"number"];	
  
	
  	
  	
  	
  _state	
  =	
  [coder	
  decodeUnsignedIntegerForKey:@"state"];	
  
	
  	
  	
  	
  _title	
  =	
  [coder	
  decodeObjectForKey:@"title"];	
  
	
  	
  	
  	
  _body	
  =	
  [coder	
  decodeObjectForKey:@"body"];	
  
	
  	
  	
  	
  _reporterLogin	
  =	
  [coder	
  
decodeObjectForKey:@"reporterLogin"];	
  
	
  	
  	
  	
  _assignee	
  =	
  [coder	
  decodeObjectForKey:@"assignee"];	
  
	
  	
  	
  	
  _updatedAt	
  =	
  [coder	
  decodeObjectForKey:@"updatedAt"];	
  
!
	
  	
  	
  	
  return	
  self;	
  
}

Dominik Gruber	

@the_dom
-­‐	
  (void)encodeWithCoder:(NSCoder	
  *)coder	
  {	
  
	
  	
  	
  	
  if	
  (self.URL	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.URL	
  forKey:@"URL"];	
  
	
  	
  	
  	
  if	
  (self.HTMLURL	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.HTMLURL	
  forKey:@"HTMLURL"];	
  
	
  	
  	
  	
  if	
  (self.number	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.number	
  forKey:@"number"];	
  
	
  	
  	
  	
  if	
  (self.title	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.title	
  forKey:@"title"];	
  
	
  	
  	
  	
  if	
  (self.body	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.body	
  forKey:@"body"];	
  
	
  	
  	
  	
  if	
  (self.reporterLogin	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.reporterLogin	
  
forKey:@"reporterLogin"];	
  
	
  	
  	
  	
  if	
  (self.assignee	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.assignee	
  forKey:@"assignee"];	
  
	
  	
  	
  	
  if	
  (self.updatedAt	
  !=	
  nil)	
  
	
  	
  	
  	
  	
  	
  	
  	
  [coder	
  encodeObject:self.updatedAt	
  forKey:@"updatedAt"];	
  

!
	
  	
  	
  	
  [coder	
  encodeUnsignedInteger:self.state	
  forKey:@"state"];	
  
}

Dominik Gruber	

@the_dom
-­‐	
  (id)copyWithZone:(NSZone	
  *)zone	
  {	
  
	
  	
  	
  	
  GHIssue	
  *issue	
  =	
  [[self.class	
  allocWithZone:zone]	
  init];	
  
	
  	
  	
  	
  issue-­‐>_URL	
  =	
  self.URL;	
  
	
  	
  	
  	
  issue-­‐>_HTMLURL	
  =	
  self.HTMLURL;	
  
	
  	
  	
  	
  issue-­‐>_number	
  =	
  self.number;	
  
	
  	
  	
  	
  issue-­‐>_state	
  =	
  self.state;	
  
	
  	
  	
  	
  issue-­‐>_reporterLogin	
  =	
  self.reporterLogin;	
  
	
  	
  	
  	
  issue-­‐>_assignee	
  =	
  self.assignee;	
  
	
  	
  	
  	
  issue-­‐>_updatedAt	
  =	
  self.updatedAt;	
  
!
	
  	
  	
  	
  issue.title	
  =	
  self.title;	
  
	
  	
  	
  	
  issue.body	
  =	
  self.body;	
  
}

Dominik Gruber	

@the_dom
-­‐	
  (NSUInteger)hash	
  {	
  
	
  	
  	
  	
  return	
  self.number.hash;	
  
}	
  
!
-­‐	
  (BOOL)isEqual:(GHIssue	
  *)issue	
  {	
  
	
  	
  	
  	
  if	
  (![issue	
  isKindOfClass:GHIssue.class])	
  return	
  NO;	
  
!
	
  	
  	
  	
  return	
  [self.number	
  isEqual:issue.number]	
  &&	
  
[self.title	
  isEqual:issue.title]	
  &&	
  [self.body	
  
isEqual:issue.body];	
  
}	
  

Dominik Gruber	

@the_dom
Mantle
• Simple Model Layer for iOS and OS X	

• Currently Version 1.2	

• First release in October 2012	

• Developed by GitHub

https://github.com/github/Mantle

Dominik Gruber	

@the_dom
typedef	
  enum	
  :	
  NSUInteger	
  {	
  
	
  	
  	
  	
  GHIssueStateOpen,	
  
	
  	
  	
  	
  GHIssueStateClosed	
  
}	
  GHIssueState;	
  

!
@interface	
  GHIssue	
  :	
  MTLModel	
  <MTLJSONSerializing>	
  

!
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSURL	
  *URL;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSURL	
  *HTMLURL;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSNumber	
  *number;	
  
@property	
  (nonatomic,	
  assign,	
  readonly)	
  GHIssueState	
  state;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSString	
  *reporterLogin;	
  
@property	
  (nonatomic,	
  strong,	
  readonly)	
  GHUser	
  *assignee;	
  
@property	
  (nonatomic,	
  copy,	
  readonly)	
  NSDate	
  *updatedAt;	
  

!
@property	
  (nonatomic,	
  copy)	
  NSString	
  *title;	
  
@property	
  (nonatomic,	
  copy)	
  NSString	
  *body;	
  

!
@end

Dominik Gruber	

@the_dom
@implementation	
  GHIssue	
  
!
+	
  (NSDictionary	
  *)JSONKeyPathsByPropertyKey	
  {	
  
	
  	
  	
  	
  return	
  @{	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"URL":	
  @"url",	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"HTMLURL":	
  @"html_url",	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"reporterLogin":	
  @"user.login",	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"assignee":	
  @"assignee",	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"updatedAt":	
  @"updated_at"	
  
	
  	
  	
  	
  };	
  
}	
  

Dominik Gruber	

@the_dom
+	
  (NSValueTransformer	
  *)URLJSONTransformer	
  {	
  
	
  	
  	
  	
  return	
  [NSValueTransformer	
  
valueTransformerForName:MTLURLValueTransformerName];	
  
}	
  

!
+	
  (NSValueTransformer	
  *)stateJSONTransformer	
  {	
  
	
  	
  	
  	
  NSDictionary	
  *states	
  =	
  @{	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"open":	
  @(GHIssueStateOpen),	
  
	
  	
  	
  	
  	
  	
  	
  	
  @"closed":	
  @(GHIssueStateClosed)	
  
	
  	
  	
  	
  };	
  

!
	
  	
  	
  	
  return	
  [MTLValueTransformer	
  
reversibleTransformerWithForwardBlock:^(NSString	
  *str)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  states[str];	
  
	
  	
  	
  	
  }	
  reverseBlock:^(NSNumber	
  *state)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  [states	
  allKeysForObject:state].lastObject;	
  
	
  	
  	
  	
  }];	
  
}

Dominik Gruber	

@the_dom
+
•

•
•

Automatically implemented	


•
•
•
•

<NSCoding>!
<NSCopying>!
-­‐isEqual:!
-­‐hash	
  

[MTLJSONAdapter	
  JSONDictionaryFromModel:]	
  
It’s possible to handle interface changes with Mantle
Dominik Gruber	

@the_dom
•
•
•

Bad documentation	

No persistence	

Some pitfalls

Dominik Gruber	

@the_dom
Persistence
// Persisting
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[self encodeWithCoder:archiver];
[archiver finishEncoding];
[data writeToFile:[self storagePath] atomically:YES];

Dominik Gruber	

@the_dom
Persistence
// Loading
id item = nil;
NSString *path = [self storagePathForItemId:itemId];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSData *data = [NSData dataWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver
alloc] initForReadingWithData:data];
item = [[[self class] alloc] initWithCoder:unarchiver];
[unarchiver finishDecoding];
}

Dominik Gruber	

@the_dom
How does it work?
// NSKeyValueCoding
if (![obj validateValue:&validatedValue forKey:key
error:error]) {
return NO;
}
!
if (value != validatedValue) {
[obj setValue:validatedValue forKey:key];
}

Dominik Gruber	

@the_dom
Q &A

Dominik Gruber	

@the_dom

More Related Content

What's hot

Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
Whymca
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Using Node.js to  Build Great  Streaming Services - HTML5 Dev ConfUsing Node.js to  Build Great  Streaming Services - HTML5 Dev Conf
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Tom Croucher
 

What's hot (20)

Talk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe ConversetTalk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe Converset
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and Python
 
Beyond Phoenix
Beyond PhoenixBeyond Phoenix
Beyond Phoenix
 
How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Mongoose: MongoDB object modelling for Node.js
Mongoose: MongoDB object modelling for Node.jsMongoose: MongoDB object modelling for Node.js
Mongoose: MongoDB object modelling for Node.js
 
A single language for backend and frontend from AngularJS to cloud with Clau...
A single language for backend and frontend  from AngularJS to cloud with Clau...A single language for backend and frontend  from AngularJS to cloud with Clau...
A single language for backend and frontend from AngularJS to cloud with Clau...
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On Steroids
 
Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
 
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Using Node.js to  Build Great  Streaming Services - HTML5 Dev ConfUsing Node.js to  Build Great  Streaming Services - HTML5 Dev Conf
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
 
Q
QQ
Q
 
"The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi..."The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi...
 
Whats new in iOS5
Whats new in iOS5Whats new in iOS5
Whats new in iOS5
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
Node.js - A Quick Tour
Node.js - A Quick TourNode.js - A Quick Tour
Node.js - A Quick Tour
 
Web Scraping with PHP
Web Scraping with PHPWeb Scraping with PHP
Web Scraping with PHP
 
When RSS Fails: Web Scraping with HTTP
When RSS Fails: Web Scraping with HTTPWhen RSS Fails: Web Scraping with HTTP
When RSS Fails: Web Scraping with HTTP
 

Viewers also liked

Viewers also liked (14)

Visual resume
Visual resumeVisual resume
Visual resume
 
Programación Estructurada Unidad 2 Practica 4-B
Programación Estructurada Unidad 2 Practica 4-BProgramación Estructurada Unidad 2 Practica 4-B
Programación Estructurada Unidad 2 Practica 4-B
 
Visual resume
Visual resumeVisual resume
Visual resume
 
Programación Estructurada Unidad 2 Practica 3
Programación Estructurada Unidad 2 Practica 3Programación Estructurada Unidad 2 Practica 3
Programación Estructurada Unidad 2 Practica 3
 
Programación Estructurada Unidad 2 Practica 4-A
Programación Estructurada Unidad 2 Practica 4-AProgramación Estructurada Unidad 2 Practica 4-A
Programación Estructurada Unidad 2 Practica 4-A
 
My Visual resume
My Visual resumeMy Visual resume
My Visual resume
 
my Visual resume 2014
my Visual resume 2014my Visual resume 2014
my Visual resume 2014
 
Selling to-the-federal-government1291
Selling to-the-federal-government1291Selling to-the-federal-government1291
Selling to-the-federal-government1291
 
2015-04-15 | Apache Kafka (Vienna Scala User Group)
2015-04-15 | Apache Kafka (Vienna Scala User Group)2015-04-15 | Apache Kafka (Vienna Scala User Group)
2015-04-15 | Apache Kafka (Vienna Scala User Group)
 
Programacion Estructurada Unidad 3 Practica 6
Programacion Estructurada Unidad 3 Practica 6Programacion Estructurada Unidad 3 Practica 6
Programacion Estructurada Unidad 3 Practica 6
 
Visual resume
Visual resumeVisual resume
Visual resume
 
2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna...
2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna...2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna...
2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna...
 
Programación Estructurada Unidad 2 Ejercicios del 20 de Febrero
Programación Estructurada Unidad 2 Ejercicios del 20 de FebreroProgramación Estructurada Unidad 2 Ejercicios del 20 de Febrero
Programación Estructurada Unidad 2 Ejercicios del 20 de Febrero
 
Programacion Estructurada Unidad 3 Practica 5
Programacion Estructurada Unidad 3 Practica 5Programacion Estructurada Unidad 3 Practica 5
Programacion Estructurada Unidad 3 Practica 5
 

Similar to 2013-08-08 | Mantle (Cocoaheads Vienna)

Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Sarp Erdag
 
the next web now
the next web nowthe next web now
the next web now
zulin Gu
 
Dev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDBDev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDB
MongoDB
 
iOS 2 - The practical Stuff
iOS 2 - The practical StuffiOS 2 - The practical Stuff
iOS 2 - The practical Stuff
Petr Dvorak
 

Similar to 2013-08-08 | Mantle (Cocoaheads Vienna) (20)

Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5
 
iOS5 NewStuff
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
 
Developing iOS REST Applications
Developing iOS REST ApplicationsDeveloping iOS REST Applications
Developing iOS REST Applications
 
Modernize your Objective-C
Modernize your Objective-CModernize your Objective-C
Modernize your Objective-C
 
Future-proof Development for Classic SharePoint
Future-proof Development for Classic SharePointFuture-proof Development for Classic SharePoint
Future-proof Development for Classic SharePoint
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sites
 
the next web now
the next web nowthe next web now
the next web now
 
Dev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDBDev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDB
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web Apps
 
Modernizes your objective C - Oliviero
Modernizes your objective C - OlivieroModernizes your objective C - Oliviero
Modernizes your objective C - Oliviero
 
Pioc
PiocPioc
Pioc
 
DevOps Fest 2020. Alexey Golub. GitHub Actions in action
DevOps Fest 2020. Alexey Golub. GitHub Actions in actionDevOps Fest 2020. Alexey Golub. GitHub Actions in action
DevOps Fest 2020. Alexey Golub. GitHub Actions in action
 
Alexey Golub - Dependency absolution (application as a pipeline) | Svitla Sma...
Alexey Golub - Dependency absolution (application as a pipeline) | Svitla Sma...Alexey Golub - Dependency absolution (application as a pipeline) | Svitla Sma...
Alexey Golub - Dependency absolution (application as a pipeline) | Svitla Sma...
 
iOS 2 - The practical Stuff
iOS 2 - The practical StuffiOS 2 - The practical Stuff
iOS 2 - The practical Stuff
 
Annotation processing tool
Annotation processing toolAnnotation processing tool
Annotation processing tool
 
Dartprogramming
DartprogrammingDartprogramming
Dartprogramming
 
New Features of JSR 317 (JPA 2.0)
New Features of JSR 317 (JPA 2.0)New Features of JSR 317 (JPA 2.0)
New Features of JSR 317 (JPA 2.0)
 
GitHub Actions in action
GitHub Actions in actionGitHub Actions in action
GitHub Actions in action
 
Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.
 

Recently uploaded

Recently uploaded (20)

presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 

2013-08-08 | Mantle (Cocoaheads Vienna)

  • 2. Agenda • • • • Context Core Data Alternatives to Core Data Mantle Dominik Gruber @the_dom
  • 3.
  • 4. Core Data • • Obvious choice • • Well-documented It works But... • • • It’s slow No direct SQL queries A lot of boilerplate Dominik Gruber @the_dom
  • 5. Why is Core Data SO slow? • • • No mass update/delete Synchronization between NSManagedObjectContext   No transactions Dominik Gruber @the_dom
  • 7. NSCoder “(...) the interface used by concrete subclasses to transfer objects and other Objective-C data items between memory and some other format. This capability provides the basis for archiving and distribution.” Dominik Gruber @the_dom
  • 8. typedef  enum  :  NSUInteger  {          GHIssueStateOpen,          GHIssueStateClosed   }  GHIssueState;   ! @interface  GHIssue  :  NSObject  <NSCoding,  NSCopying>   ! @property  (nonatomic,  copy,  readonly)  NSURL  *URL;   @property  (nonatomic,  copy,  readonly)  NSURL  *HTMLURL;   @property  (nonatomic,  copy,  readonly)  NSNumber  *number;   @property  (nonatomic,  assign,  readonly)  GHIssueState  state;   @property  (nonatomic,  copy,  readonly)  NSString  *reporterLogin;   @property  (nonatomic,  copy,  readonly)  NSDate  *updatedAt;   @property  (nonatomic,  strong,  readonly)  GHUser  *assignee;   ! @property  (nonatomic,  copy)  NSString  *title;   @property  (nonatomic,  copy)  NSString  *body;   ! -­‐  (id)initWithDictionary:(NSDictionary  *)dictionary;   ! @end Dominik Gruber @the_dom
  • 9. -­‐  (id)initWithDictionary:(NSDictionary  *)dictionary  {          self  =  [self  init];          if  (self  ==  nil)  return  nil;   !        _URL  =  [NSURL  URLWithString:dictionary[@"url"]];          _HTMLURL  =  [NSURL  URLWithString:dictionary[@"html_url"]];          _number  =  dictionary[@"number"];   !        if  ([dictionary[@"state"]  isEqualToString:@"open"])  {                  _state  =  GHIssueStateOpen;          }  else  if  ([dictionary[@"state"]  isEqualToString:@"closed"])  {                  _state  =  GHIssueStateClosed;          }   !        _title  =  [dictionary[@"title"]  copy];          _body  =  [dictionary[@"body"]  copy];          _reporterLogin  =  [dictionary[@"user"][@"login"]  copy];          _assignee  =  [[GHUser  alloc]   initWithDictionary:dictionary[@"assignee"]];   !        _updatedAt  =  [self.class.dateFormatter   dateFromString:dictionary[@"updated_at"]];   !        return  self;   Dominik Gruber @the_dom
  • 10. -­‐  (id)initWithCoder:(NSCoder  *)coder  {          self  =  [self  init];          if  (self  ==  nil)  return  nil;   !        _URL  =  [coder  decodeObjectForKey:@"URL"];          _HTMLURL  =  [coder  decodeObjectForKey:@"HTMLURL"];          _number  =  [coder  decodeObjectForKey:@"number"];          _state  =  [coder  decodeUnsignedIntegerForKey:@"state"];          _title  =  [coder  decodeObjectForKey:@"title"];          _body  =  [coder  decodeObjectForKey:@"body"];          _reporterLogin  =  [coder   decodeObjectForKey:@"reporterLogin"];          _assignee  =  [coder  decodeObjectForKey:@"assignee"];          _updatedAt  =  [coder  decodeObjectForKey:@"updatedAt"];   !        return  self;   } Dominik Gruber @the_dom
  • 11. -­‐  (void)encodeWithCoder:(NSCoder  *)coder  {          if  (self.URL  !=  nil)                  [coder  encodeObject:self.URL  forKey:@"URL"];          if  (self.HTMLURL  !=  nil)                  [coder  encodeObject:self.HTMLURL  forKey:@"HTMLURL"];          if  (self.number  !=  nil)                  [coder  encodeObject:self.number  forKey:@"number"];          if  (self.title  !=  nil)                  [coder  encodeObject:self.title  forKey:@"title"];          if  (self.body  !=  nil)                  [coder  encodeObject:self.body  forKey:@"body"];          if  (self.reporterLogin  !=  nil)                  [coder  encodeObject:self.reporterLogin   forKey:@"reporterLogin"];          if  (self.assignee  !=  nil)                  [coder  encodeObject:self.assignee  forKey:@"assignee"];          if  (self.updatedAt  !=  nil)                  [coder  encodeObject:self.updatedAt  forKey:@"updatedAt"];   !        [coder  encodeUnsignedInteger:self.state  forKey:@"state"];   } Dominik Gruber @the_dom
  • 12. -­‐  (id)copyWithZone:(NSZone  *)zone  {          GHIssue  *issue  =  [[self.class  allocWithZone:zone]  init];          issue-­‐>_URL  =  self.URL;          issue-­‐>_HTMLURL  =  self.HTMLURL;          issue-­‐>_number  =  self.number;          issue-­‐>_state  =  self.state;          issue-­‐>_reporterLogin  =  self.reporterLogin;          issue-­‐>_assignee  =  self.assignee;          issue-­‐>_updatedAt  =  self.updatedAt;   !        issue.title  =  self.title;          issue.body  =  self.body;   } Dominik Gruber @the_dom
  • 13. -­‐  (NSUInteger)hash  {          return  self.number.hash;   }   ! -­‐  (BOOL)isEqual:(GHIssue  *)issue  {          if  (![issue  isKindOfClass:GHIssue.class])  return  NO;   !        return  [self.number  isEqual:issue.number]  &&   [self.title  isEqual:issue.title]  &&  [self.body   isEqual:issue.body];   }   Dominik Gruber @the_dom
  • 14. Mantle • Simple Model Layer for iOS and OS X • Currently Version 1.2 • First release in October 2012 • Developed by GitHub
 https://github.com/github/Mantle Dominik Gruber @the_dom
  • 15. typedef  enum  :  NSUInteger  {          GHIssueStateOpen,          GHIssueStateClosed   }  GHIssueState;   ! @interface  GHIssue  :  MTLModel  <MTLJSONSerializing>   ! @property  (nonatomic,  copy,  readonly)  NSURL  *URL;   @property  (nonatomic,  copy,  readonly)  NSURL  *HTMLURL;   @property  (nonatomic,  copy,  readonly)  NSNumber  *number;   @property  (nonatomic,  assign,  readonly)  GHIssueState  state;   @property  (nonatomic,  copy,  readonly)  NSString  *reporterLogin;   @property  (nonatomic,  strong,  readonly)  GHUser  *assignee;   @property  (nonatomic,  copy,  readonly)  NSDate  *updatedAt;   ! @property  (nonatomic,  copy)  NSString  *title;   @property  (nonatomic,  copy)  NSString  *body;   ! @end Dominik Gruber @the_dom
  • 16. @implementation  GHIssue   ! +  (NSDictionary  *)JSONKeyPathsByPropertyKey  {          return  @{                  @"URL":  @"url",                  @"HTMLURL":  @"html_url",                  @"reporterLogin":  @"user.login",                  @"assignee":  @"assignee",                  @"updatedAt":  @"updated_at"          };   }   Dominik Gruber @the_dom
  • 17. +  (NSValueTransformer  *)URLJSONTransformer  {          return  [NSValueTransformer   valueTransformerForName:MTLURLValueTransformerName];   }   ! +  (NSValueTransformer  *)stateJSONTransformer  {          NSDictionary  *states  =  @{                  @"open":  @(GHIssueStateOpen),                  @"closed":  @(GHIssueStateClosed)          };   !        return  [MTLValueTransformer   reversibleTransformerWithForwardBlock:^(NSString  *str)  {                  return  states[str];          }  reverseBlock:^(NSNumber  *state)  {                  return  [states  allKeysForObject:state].lastObject;          }];   } Dominik Gruber @the_dom
  • 18. + • • • Automatically implemented • • • • <NSCoding>! <NSCopying>! -­‐isEqual:! -­‐hash   [MTLJSONAdapter  JSONDictionaryFromModel:]   It’s possible to handle interface changes with Mantle Dominik Gruber @the_dom
  • 19. • • • Bad documentation No persistence Some pitfalls Dominik Gruber @the_dom
  • 20. Persistence // Persisting NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; [self encodeWithCoder:archiver]; [archiver finishEncoding]; [data writeToFile:[self storagePath] atomically:YES]; Dominik Gruber @the_dom
  • 21. Persistence // Loading id item = nil; NSString *path = [self storagePathForItemId:itemId]; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { NSData *data = [NSData dataWithContentsOfFile:path]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; item = [[[self class] alloc] initWithCoder:unarchiver]; [unarchiver finishDecoding]; } Dominik Gruber @the_dom
  • 22. How does it work? // NSKeyValueCoding if (![obj validateValue:&validatedValue forKey:key error:error]) { return NO; } ! if (value != validatedValue) { [obj setValue:validatedValue forKey:key]; } Dominik Gruber @the_dom