More Related Content Similar to 2013-08-08 | Mantle (Cocoaheads Vienna) (20) 2013-08-08 | Mantle (Cocoaheads Vienna)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
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