Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NSPredicates for Fun and Profit
Search
kognate
August 11, 2012
2
200
NSPredicates for Fun and Profit
Slides presented at CocoaConf 2012
kognate
August 11, 2012
Tweet
Share
More Decks by kognate
See All by kognate
DSLs And Extension Languages
kognate
1
110
CodeMash Prolog Talk 2012
kognate
3
200
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Producing Creativity
orderedlist
PRO
341
39k
Faster Mobile Websites
deanohume
305
30k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
[RailsConf 2023] Rails as a piece of cake
palkan
51
4.9k
Designing Experiences People Love
moore
138
23k
Practical Orchestrator
shlominoach
186
10k
Transcript
NSPredicates For Fun and Profit Friday, August 10, 12
An NSPredicate is a Query Friday, August 10, 12
What’s it for? • string stuff • filtering arrays •
Core Data • Spotlight Friday, August 10, 12
It’s in Foundation Friday, August 10, 12
What’s it for? • string stuff • filtering • Core
Data • Spotlight Friday, August 10, 12
Creating NSPredicates Friday, August 10, 12
[NSPredicate predicateWithFormat:@”FORMAT_STRING”,args] Friday, August 10, 12
[NSPredicate predicateWithFormat:@”SELF contains %@”,@”hello”] Friday, August 10, 12
[NSPredicate predicateWithFormat:@”SELF contains %@”,@”hello”] NSPredicate *greeting = [NSPredicate predicateWithFormat:@"SELF contains
%@",@"hello"]; BOOL greeted = [greeting evaluateWithObject:@"hello world"]; NSLog(@"Greeted? %d",greeted); Friday, August 10, 12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
BEGINSWITH NSPredicate *beginswith = [NSPredicate predicateWithFormat:@"self beginswith %@",@"begins"]; NSLog(@"Begins with:
%d",[beginswith evaluateWithObject:@"beginswith"]); NSLog(@"Begins with: %d",[beginswith evaluateWithObject:@"wbeginswith"]); Friday, August 10, 12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
CONTAINS NSPredicate *contains = [NSPredicate predicateWithFormat:@"self contains[cd] %@",@"past"]; NSLog(@"Contains string:
%d", [contains evaluateWithObject:@"The past isn't done with you"]); NSLog(@"Contains string: %d",[contains evaluateWithObject:@"PaSt"]); Friday, August 10, 12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
ENDSWITH NSPredicate *endswith = [NSPredicate predicateWithFormat:@"self endswith %@",@"world"]; NSLog(@"Endswith string:
%d",[endswith evaluateWithObject:@"hello world"]); NSLog(@"Endswith string: %d",[endswith evaluateWithObject:@"hello world?"]); Friday, August 10, 12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
LIKE NSPredicate *like = [NSPredicate predicateWithFormat:@"self lik %@",@"*like?"]; NSLog(@"Is Like:
%d", [like evaluateWithObject:@"likeable"]); NSLog(@"Is Like: %d", [like evaluateWithObject:@"is likeable"]) NSLog(@"Is Like: %d", [like evaluateWithObject:@"likes"]); NSLog(@"Is Like: %d", [like evaluateWithObject:@"wiliked"]); Friday, August 10, 12
String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,
12
MATCHES NSPredicate *match = [NSPredicate predicateWithFormat:@"self matches '\\\\d+[a-z]'"]; NSLog(@"Regex match:
%d", [match evaluateWithObject:@"0A"]); NSLog(@"Regex match: %d", [match evaluateWithObject:@"0a"]); NSLog(@"Regex match: %d", [match evaluateWithObject:@"000000ab"]); NSLog(@"Regex match: %d", [match evaluateWithObject:@"000000c"]); Friday, August 10, 12
Strings • String begins with ‘CH’ • longer than 3
chars • does NOT contain ‘broken’ • shorter than 20 chars • contains at least one digit • contains NO spaces Friday, August 10, 12
- (BOOL) thisIsTerrible:(NSString *) _myarg { BOOL _res = NO;
if ([[_myarg substringToIndex:2] isEqualToString:@"CH"]) { if ([_myarg length] > 3) { if ([[_myarg componentsSeparatedByString:@"broken"] count] 1) { if ([_myarg length] < 20) { NSCharacterSet *s = [NSCharacterSet decimalDigitCharacterSet]; if ([[_myarg componentsSeparatedByCharactersInSet: count] > 1) { if ([[_myarg componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] count] == 1) { _res = YES; } } } } } } return _res; } Friday, August 10, 12
- (BOOL) predicatesTIT:(NSString *)_myarg { NSPredicate *beginsWithCH = [NSPredicate predicateWithFormat:@"SELF
beginswith 'CH'"]; NSPredicate *longEnough = [NSPredicate predicateWithFormat:@"SELF.length > 3"]; NSPredicate *shortEnough = [NSPredicate predicateWithFormat:@"SELF.length < 20"]; NSPredicate *containsDigit = [NSPredicate predicateWithFormat:@"SELF matches '.* \\\\d.*'"]; NSPredicate *containsSpace = [NSPredicate predicateWithFormat:@"SELF contains ' '"]; NSPredicate *containsBroken = [NSPredicate predicateWithFormat:@"SELF contains 'broken'"]; NSPredicate *notContainsBroken = [NSCompoundPredicate notPredicateWithSubpredicate:containsBroken]; NSPredicate *notCOntainsSpace = [NSCompoundPredicate notPredicateWithSubpredicate:containsSpace]; NSArray *_preds = [NSArray arrayWithObjects:beginsWithCH, longEnough, shortEnough, notContainsBroken, notCOntainsString, containsDigit, nil]; NSPredicate *main = [NSCompoundPredicate andPredicateWithSubpredicates:_preds]; return [main evaluateWithObject:_myarg]; } Friday, August 10, 12
- (BOOL) predicatesTITshort:(NSString *)_myarg { NSPredicate *one = [NSPredicate predicateWithFormat:@"SELF
beginswith 'CH'"]; NSPredicate *two = [NSPredicate predicateWithFormat:@"SELF.length > 3 AND self.length < 20"]; NSPredicate *three = [NSPredicate predicateWithFormat:@"SELF matches '.*\\\\d.*' and NOT(SELF contains ' ') and NOT(SELF contains 'broken')"]; NSArray *_preds = [NSArray arrayWithObjects:one,two,three,nil]; NSPredicate *main = [NSCompoundPredicate andPredicateWithSubpredicates:_preds]; return [main evaluateWithObject:_myarg]; } Friday, August 10, 12
But then things change Friday, August 10, 12
Strings • String begins with ‘CH’ • longer than 3
chars • does NOT contain ‘broken’ • shorter than 20 chars • contains at least one digit • contains NO spaces Friday, August 10, 12
Strings • String begins with ‘CH’ or ‘HC’ • longer
than 3 chars • does NOT contain ‘broken’ • contains ‘broken’ if string starts with ‘HC’ • shorter than 20 chars • contains at least one digit • contains NO spaces Friday, August 10, 12
- (BOOL) thisIsReallyTerrible:(NSString *)_myarg { BOOL _res = NO; if
([_myarg length] > 3) { if ([_myarg length] < 20) { NSCharacterSet *s = [NSCharacterSet decimalDigitCharacterSet]; if ([[_myarg componentsSeparatedByCharactersInSet:s] count] > 1) { NSCharacterSet *w = [NSCharacterSet whitespaceCharacterSet]; if ([[_myarg componentsSeparatedByCharactersInSet:w] count] == 1) { if ([[_myarg substringToIndex:2] isEqualToString:@"CH"]) { if ([[_myarg componentsSeparatedByString:@"broken"] count] == 1) { _res = YES; } } else if ([[_myarg substringToIndex:2] isEqualToString:@"HC"]) { if ([[_myarg componentsSeparatedByString:@"broken"] count] > 1) { _res = YES; } } } } } } return _res; } Friday, August 10, 12
- (BOOL) predicatesTIRT:(NSString *)_myarg { NSPredicate *beginsWithCH = [NSPredicate predicateWithFormat:@"SELF
beginswith 'CH'"]; NSPredicate *beginsWithHC = [NSPredicate predicateWithFormat:@"SELF beginswith 'HC'"]; NSPredicate *longEnough = [NSPredicate predicateWithFormat:@"SELF.length > 3"]; NSPredicate *shortEnough = [NSPredicate predicateWithFormat:@"SELF.length < 20"]; NSPredicate *containsDigit = [NSPredicate predicateWithFormat:@"SELF matches '.*\\\\d.*'"]; NSPredicate *containsSpace = [NSPredicate predicateWithFormat:@"SELF contains ' '"]; NSPredicate *containsBroken = [NSPredicate predicateWithFormat:@"SELF contains 'broken'"]; NSPredicate *notCB = [NSCompoundPredicate notPredicateWithSubpredicate:containsBroken]; NSPredicate *notCS = [NSCompoundPredicate notPredicateWithSubpredicate:containsSpace]; NSArray *_ch = [NSArray arrayWithObjects:beginsWithCH,notCB, nil]; NSPredicate *chnotbroken = [NSCompoundPredicate andPredicateWithSubpredicates:_ch]; NSArray *_hc = [NSArray arrayWithObjects:beginsWithHC,containsBroken,nil]; NSPredicate *hcbroken = [NSCompoundPredicate andPredicateWithSubpredicates:_hc]; NSArray *_chhc = [NSArray arrayWithObjects:chnotbroken,hcbroken, nil]; NSPredicate *begins = [NSCompoundPredicate orPredicateWithSubpredicates:_chhc]; NSArray *_preds = [NSArray arrayWithObjects:begins, longEnough, shortEnough, containsDigit, notCS, nil]; NSPredicate *main = [NSCompoundPredicate andPredicateWithSubpredicates:_preds]; return [main evaluateWithObject:_myarg]; } Friday, August 10, 12
MATCHES validation NSPredicate *_emailValid = [NSPredicate predicateWithFormat:@"self matches '[a-z+] +@[a-z]+\\\\.com'"];
return [_emailValid evaluateWithObject:email]; Friday, August 10, 12
Filtering Arrays • mutable and immutable • works great for
table views Friday, August 10, 12
Simple Filtering NSArray *_start = [NSArray arrayWithObjects:NSNum(1),NSNum(3),NSNum(5),NSNum(7),NSNum(8),ni l]; NSPredicate *_filter
= [NSPredicate predicateWithFormat:@"self in {1,5,7}"]; return [_start filteredArrayUsingPredicate:_filter]; #define NSNum(arg) [NSNumber numberWithInt:arg] Friday, August 10, 12
Mutable Filter NSPredicate *_filter = [NSPredicate predicateWithFormat:@"self in {1,5,7}"]; [_mutable
filterUsingPredicate:_filter]; Friday, August 10, 12
Key Paths NSDictionary *_done = [NSDictionary dictionaryWithObjectsAndKeys: @"Sam", @"Firstname", [NSDate
date],@"Birthday", nil]; NSDictionary *_dtwo = [NSDictionary dictionaryWithObjectsAndKeys:@"Alice",@"Firstname",[NSDate date],@"Birthday", nil]; NSDictionary *_dthree = [NSDictionary dictionaryWithObjectsAndKeys:@"Amy",@"Firstname",nil]; NSArray *_ar = [NSArray arrayWithObjects:_done,_dtwo,_dthree,nil]; NSPredicate *_pred = [NSPredicate predicateWithFormat:@"Birthday != nil && Firstname != nil"]; NSArray *_res = [_ar filteredArrayUsingPredicate:_pred]; NSLog(@"%@",_res); return _res; Friday, August 10, 12
Not All Keys Nest NSDictionary *_ndone = [NSDictionary dictionaryWithObjectsAndKeys:[NSDate date],@"Date",
nil]; NSDictionary *_done = [NSDictionary dictionaryWithObjectsAndKeys:@"Sam",@"Firstname",_ndone,@"Birthday", nil]; NSDictionary *_dtwo = [NSDictionary dictionaryWithObjectsAndKeys:@"Alice",@"Firstname",[NSDate date],@"Birthday", nil]; NSDictionary *_dthree = [NSDictionary dictionaryWithObjectsAndKeys:@"Amy",@"Firstname",nil]; NSArray *_ar = [NSArray arrayWithObjects:_done,_dtwo,_dthree,nil]; NSPredicate *_pred = [NSPredicate predicateWithFormat:@"Birthday.Date != nil && Firstname != nil"]; NSArray *_res = [_ar filteredArrayUsingPredicate:_pred]; return _res; Friday, August 10, 12
Other ways to define NSPredicate *_pred = [NSPredicate predicateWithBlock:^BOOL(NSArray *obj,
NSDictionary *bindings) { BOOL _lengthGood = [obj count] > 3; NSUInteger idx = [obj indexOfObject:[NSNumber numberWithInt:20]]; return _lengthGood && idx; }]; return [_pred evaluateWithObject:_array]; Friday, August 10, 12
Core Data IS NOT SQL Friday, August 10, 12
You Can’t Do This select SOMETABLE.* from SOMETABLE,OTHERTABLE where SOMETABLE.column
> 3 and OTHERTABLE.othercolumn = SOMETABLE.othercolumn; Friday, August 10, 12
Object Graph Friday, August 10, 12
Friday, August 10, 12
Subquery NSFetchRequest *_fetch = [[NSFetchRequest alloc] init]; NSPredicate *_pred =
[NSPredicate predicateWithFormat: @"manager.name = 'Bill' and subquery(Employee,$e, any $e.salary > 90000)@count > 1"]; [_fetch setPredicate:_pred]; NSManagedObjectContext *context = [self managedObjectContext]; NSError *error = nil; return [[context executeFetchRequest:_fetch error:&error] lastObject]; Friday, August 10, 12
Don’t Friday, August 10, 12
Core Data Validation - (BOOL)validateValue:(id *)ioValue forKey:(NSString *)key error:(NSError **)outError
Friday, August 10, 12
Performance • It’s very fast • But it’s not magic
Friday, August 10, 12
Do • minimize the amount of work done • put
‘match’ last • avoid joins • denormalize performance sensitive data • use the right store for the right job Friday, August 10, 12
Don’t • use joins, use subqueries (sparingly) • confuse it
with SQL databases • use the wrong store Friday, August 10, 12
Remember The Compiler Can Do It Better Friday, August 10,
12
Resources • Pro Core Data for iOS • Core Data
(Zarra) • Apple’s Docs • Practice Friday, August 10, 12