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

Practical Core Data

Practical Core Data

... and a primer to Jailbroken Apple TV Application Development

Jeremy Foo

July 03, 2014
Tweet

More Decks by Jeremy Foo

Other Decks in Technology

Transcript

  1. 2

  2. NSMutableArray *finalArray = [NSMutableArray arrayWithCapacity:[initialArray count]]; for (id object in

    initialArray) { if ([object specialValue] == specialValue) [finalArray addObject:object]; } return finalArray;
  3. Store Store Persistent Store Coordinator ManagedObject Context Model Model MO

    MO ID ID MO ID MO ID MO ID MO ID MO ID MO ID MO ID
  4. Store Store Persistent Store Coordinator ManagedObject Context Model Model MO

    MO ID ID MO ID MO ID MO ID MO ID MO ID MO ID MO ID
  5. NSString *const NSManagedObjectContextWillSaveNotification NS_AVAILABLE(10_5, 3_0); NSString *const NSManagedObjectContextDidSaveNotification NS_AVAILABLE(10_4, 3_0);

    ! NSString *const NSManagedObjectContextObjectsDidChangeNotification NS_AVAILABLE(10_4, 3_0); ! NSString *const NSInsertedObjectsKey NS_AVAILABLE(10_4, 3_0); NSString *const NSUpdatedObjectsKey NS_AVAILABLE(10_4, 3_0); NSString *const NSDeletedObjectsKey NS_AVAILABLE(10_4, 3_0); ! NSString *const NSRefreshedObjectsKey NS_AVAILABLE(10_5, 3_0); NSString *const NSInvalidatedObjectsKey NS_AVAILABLE(10_5, 3_0); ! NSString *const NSInvalidatedAllObjectsKey NS_AVAILABLE(10_5, 3_0);
  6. enum { NSConfinementConcurrencyType = 0x00, NSPrivateQueueConcurrencyType = 0x01, NSMainQueueConcurrencyType =

    0x02 }; typedef NSUInteger NSManagedObjectContextConcurrencyType; ! #if NS_BLOCKS_AVAILABLE - (void)performBlock:(void (^)())block NS_AVAILABLE(10_7, 5_0); - (void)performBlockAndWait:(void (^)())block NS_AVAILABLE(10_7, 5_0); #endif /* NS_BLOCKS_AVAILABLE */
  7. __block NSManagedObjectContext *context1 = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivat __block NSManagedObjectContext *context2

    = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQu __block NSManagedObjectContext *context3 = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivat [context3 performBlockAndWait:^{ // .. do work [context3 save:nil]; [context2 performBlockAndWait:^{ [context2 save:nil]; [context1 performBlockAndWait:^{ [context1 save:nil]; }]; }]; }];
  8. Design Patterns are important for a reason Strict MVC usage

    will prevent cross thread contamination and access
  9. Store Persistent Store Coordinator Model Persistent Store Coordinator ManagedObject Context

    Main Thread ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context NSManagedObjectDidSaveNotification SQLite WAL*
  10. -(BOOL)updateWithJSONResult:(NSDictionary *)attributes { // checks for attributes // JSONKey =

    use specified key instead of attribute name // skip = skips this attribute for parsing // check if class matches -> Apply default value NSAssert1((![[[self class] entityName] isEqualToString:ROOT_ENTITY_NAME]), @"You have to subclass this master class", nil); ! if ([attributes count] == 0) return YES; NSEntityDescription *entity = [MManagedRoot managedObjectModel].entitiesByName[[[self class] entityName]]; ! for (NSString *attributeName in entity.attributesByName) { NSAttributeDescription *attribute = entity.attributesByName[attributeName]; if (!attribute) continue; ! // check if we should skip if (ModelUserInfoValue(attribute.userInfo[PARSE_SKIP])) continue; ! // pull attribute value from dictionary id attributeValue = (attribute.userInfo[PARSE_JSON_KEY]) ? [attributes valueForKeyPath:attribute.userInfo[PARSE_JSON_KEY]] : attributes[attributeName]; if ((!ModelUserInfoValue(attribute.userInfo[PARSE_UPDATE_IF_EXIST])) && (!attributeValue)) continue; if ((!ModelUserInfoValue(entity.userInfo[PARSE_UPDATE_IF_EXIST])) && (!attributeValue)) continue; // check if we are NSNull or nil, if we are apply value for nil/null if we actually have something in the userinfo // set nil if we have nothing in the userinfo dictionary if (([attributeValue isKindOfClass:[NSNull class]]) || (!attributeValue)) { if (attribute.userInfo[PARSE_VALUE_FOR_NULL]) { if (![attribute.userInfo[PARSE_VALUE_FOR_NULL] isEqualToString:PARSE_LEAVE_AS_SELF]) [self updateAttribute:attribute withValue:attribute.userInfo[PARSE_VALUE_FOR_NULL] transformable:YES]; } else { [self setValue:nil forKeyPath:attributeName]; } continue; } if (![self updateAttribute:attribute withValue:attributeValue transformable:NO]) { // updating the attribute was unsuccessful, meaning a class mismatch happened // we have to apply the default value if that's the case, or do nothing if // we don't have a default value if (attribute.userInfo[PARSE_DEFAULT_VALUE]) { if (![attribute.userInfo[PARSE_DEFAULT_VALUE] isEqualToString:PARSE_LEAVE_AS_SELF]) [self updateAttribute:attribute withValue:attribute.userInfo[PARSE_DEFAULT_VALUE] transformable:YES]; } else { [self setValue:nil forKeyPath:attributeName]; } continue; } MDebugErrorLog(@"Could not parse attribute (%@) from value (%@)...", attributeName, attributeValue); } ! self.deleted = @(NO); self.lastParsed = [NSDate date]; ! return YES; }
  11. +(instancetype)headlessObject { return [[self class] headlessObjectFromModel:[[self class] managedObjectModel]]; } !

    +(instancetype)headlessObjectFromModel:(NSManagedObjectModel *)model { NSEntityDescription *entity = [model.entitiesByName objectForKey:[[self class] entityName]]; if (!entity) return nil; MManagedRoot *object = [[[self class] alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; [object setHeadless:YES]; return object; }
  12. Store Persistent Store Coordinator Model Persistent Store Coordinator ManagedObject Context

    Main Thread ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context NSManagedObjectDidSaveNotification SQLite WAL*
  13. Store Persistent Store Coordinator Model Persistent Store Coordinator ManagedObject Context

    Main Thread ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context ManagedObject Context NSManagedObjectDidSaveNotification Controller MO ID MO ID MO ID MO ID MO ID MO ID
  14. -(dispatch_queue_t)writeQueue { if (!_writeQueue) { NSString *writeQueueName = [NSString stringWithFormat:@"com.minus.multiply.messages.%@.write",

    self.identifier]; _writeQueue = dispatch_queue_create([writeQueueName cStringUsingEncoding:NSUTF8StringEncoding], NULL); dispatch_queue_set_specific(_writeQueue, MMessageControllerWriteQueueIdentifyKey, &_writeQueue, NULL); } return _writeQueue; } ! -(BOOL)isWriteQueue { void *candidateQueue = dispatch_get_specific(MMessageControllerWriteQueueIdentifyKey); void *writeQueue = &_writeQueue; return (candidateQueue == writeQueue); }
  15. /** The dispatch queue for `completionBlock`. If `NULL` (default), the

    main queue is used. */ @property (nonatomic, strong) dispatch_queue_t completionQueue; ! /** The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used. */ @property (nonatomic, strong) dispatch_group_t completionGroup;
  16. // operation parameters __block id networkResponseObject = nil; __block NSError

    *networkError = nil; dispatch_semaphore_t networkSemaphore = dispatch_semaphore_create(0); AFHTTPRequestOperation *requestOperation = [[MinusAPIClient sharedClient] HTTPRequestOperationWithRequest:urlRequest success:^(AFHTTPRequestOperation *operation, id responseObject) { ! networkResponseObject = responseObject; dispatch_semaphore_signal(networkSemaphore); ! } failure:^(AFHTTPRequestOperation *operation, NSError *error) { ! networkError = error; dispatch_semaphore_signal(networkSemaphore); ! }]; [self.networkOperationQueue addOperation:requestOperation]; dispatch_semaphore_wait(networkSemaphore, DISPATCH_TIME_FOREVER);
  17. Back Row UIKit <BRResponder> <UIResponder> <BRAppliance> <UIApplication> BRController UIViewController BRMenuController

    UITableViewController BRControllerStack UINavigationController BRGridView UICollectionView BRListView UITableView