SlideShare uma empresa Scribd logo
1 de 23
Baixar para ler 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

Mais conteúdo relacionado

Mais procurados

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 ConversetCocoaHeads France
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCAWhymca
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and PythonPiXeL16
 
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]Devon Bernard
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
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.jsYuriy Bogomolov
 
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...Walter Dal Mut
 
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.jsasync_io
 
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 ...Puppet
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to NodejsGabriele Lana
 
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 ConfTom Croucher
 
"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...Fwdays
 
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 HTTPMatthew Turland
 

Mais procurados (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
 

Destaque (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
 

Semelhante a 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
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Satoshi Asano
 
Developing iOS REST Applications
Developing iOS REST ApplicationsDeveloping iOS REST Applications
Developing iOS REST Applicationslmrei
 
Modernize your Objective-C
Modernize your Objective-CModernize your Objective-C
Modernize your Objective-CMassimo Oliviero
 
Future-proof Development for Classic SharePoint
Future-proof Development for Classic SharePointFuture-proof Development for Classic SharePoint
Future-proof Development for Classic SharePointBob German
 
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 Sitesgoodfriday
 
the next web now
the next web nowthe next web now
the next web nowzulin 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 MongoDBMongoDB
 
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 AppsAdégòkè Obasá
 
Modernizes your objective C - Oliviero
Modernizes your objective C - OlivieroModernizes your objective C - Oliviero
Modernizes your objective C - OlivieroCodemotion
 
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 actionDevOps_Fest
 
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...Oleksii Holub
 
iOS 2 - The practical Stuff
iOS 2 - The practical StuffiOS 2 - The practical Stuff
iOS 2 - The practical StuffPetr Dvorak
 
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)Markus Eisele
 
GitHub Actions in action
GitHub Actions in actionGitHub Actions in action
GitHub Actions in actionOleksii Holub
 
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.UA Mobile
 

Semelhante a 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.
 

Último

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
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...Miguel Araújo
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
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 productivityPrincipled Technologies
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 

Último (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
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...
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 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
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 

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