Upgrade to Pro — share decks privately, control downloads, hide ads and more …

NSPredicates for Fun and Profit

6534d583d8b442b3be4f608a3c45b5b9?s=47 kognate
August 11, 2012
130

NSPredicates for Fun and Profit

Slides presented at CocoaConf 2012

6534d583d8b442b3be4f608a3c45b5b9?s=128

kognate

August 11, 2012
Tweet

Transcript

  1. NSPredicates For Fun and Profit Friday, August 10, 12

  2. An NSPredicate is a Query Friday, August 10, 12

  3. What’s it for? • string stuff • filtering arrays •

    Core Data • Spotlight Friday, August 10, 12
  4. It’s in Foundation Friday, August 10, 12

  5. What’s it for? • string stuff • filtering • Core

    Data • Spotlight Friday, August 10, 12
  6. Creating NSPredicates Friday, August 10, 12

  7. [NSPredicate predicateWithFormat:@”FORMAT_STRING”,args] Friday, August 10, 12

  8. [NSPredicate predicateWithFormat:@”SELF contains %@”,@”hello”] Friday, August 10, 12

  9. [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
  10. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  11. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  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
  13. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  14. 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
  15. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  16. 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
  17. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  18. 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
  19. String Matching BEGINSWITH CONTAINS ENDSWITH LIKE MATCHES Friday, August 10,

    12
  20. 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
  21. 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
  22. - (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
  23. - (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
  24. - (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
  25. But then things change Friday, August 10, 12

  26. 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
  27. 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
  28. - (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
  29. - (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
  30. MATCHES validation NSPredicate *_emailValid = [NSPredicate predicateWithFormat:@"self matches '[a-z+] +@[a-z]+\\\\.com'"];

    return [_emailValid evaluateWithObject:email]; Friday, August 10, 12
  31. Filtering Arrays • mutable and immutable • works great for

    table views Friday, August 10, 12
  32. 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
  33. Mutable Filter NSPredicate *_filter = [NSPredicate predicateWithFormat:@"self in {1,5,7}"]; [_mutable

    filterUsingPredicate:_filter]; Friday, August 10, 12
  34. 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
  35. 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
  36. 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
  37. Core Data IS NOT SQL Friday, August 10, 12

  38. You Can’t Do This select SOMETABLE.* from SOMETABLE,OTHERTABLE where SOMETABLE.column

    > 3 and OTHERTABLE.othercolumn = SOMETABLE.othercolumn; Friday, August 10, 12
  39. Object Graph Friday, August 10, 12

  40. Friday, August 10, 12

  41. 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
  42. Don’t Friday, August 10, 12

  43. Core Data Validation - (BOOL)validateValue:(id *)ioValue forKey:(NSString *)key error:(NSError **)outError

    Friday, August 10, 12
  44. Performance • It’s very fast • But it’s not magic

    Friday, August 10, 12
  45. 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
  46. Don’t • use joins, use subqueries (sparingly) • confuse it

    with SQL databases • use the wrong store Friday, August 10, 12
  47. Remember The Compiler Can Do It Better Friday, August 10,

    12
  48. Resources • Pro Core Data for iOS • Core Data

    (Zarra) • Apple’s Docs • Practice Friday, August 10, 12