Resolved verifying NSManagedObjectModel

Discussion in 'Mac Programming' started by MrFusion, Feb 26, 2011.

  1. MrFusion, Feb 26, 2011
    Last edited: Feb 26, 2011

    MrFusion macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #1
    Hi everyone

    I have a bunch of apps with pretty much the same coredata structure. A lot of common code can be placed in a subclass of NSManagedObject (CommonManagedObject). Seems ideal for a framework. This works fine, but now I want to verify during startup if the NSManagedObjectModel is implemented correctly. Every entity that uses CommonManagedObject, either directly or via a subclass, should have the same minimum set of common properties (e.g. "title").

    The code below works fine and I can use the CommonManagedObject and framework. I can identify entities that have "CommonManagedObject" as class.
    However I don't know how to identify those entities that are a subclass of CommonManagedObject. "CommonManagedObject" in this is case is nowhere defined in the model and therefore doesn't show up.
    It also doesn't show up via the superentity since these particular entities have no superentity.
    I can determine the class of the entity but the code crashes when trying to determine the superclass.

    This all happens when the app hasn't finished loading yet. So there is no NSManagedObjectContext yet or any other instances.

    Thanks!

    Code:
    +(void) load
    {
    	[super load];
    	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    	NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    	if (![CommonManagedObject verifyManagedObjectModel:model])
    		NSLog(@"Incorrect use of framework. NSManagedObjectModel does not adhere to requirements for CommonManagedObject");
    	[pool release];
    }
    
    +(BOOL) verifyManagedObjectModel:(NSManagedObjectModel *) model
    {	
    	BOOL result = TRUE;
    	NSArray *allEntities = [model entities];
    	[allEntities enumerateObjectsWithOptions:NSEnumerationConcurrent 
    								  usingBlock:^(id entityDescription, NSUInteger idx, BOOL *stop) {
    									  NSString *entityClassName = [(NSEntityDescription *)entityDescription managedObjectClassName];
    									  if (![entityClassName isEqualToString:@"NSManagedObject"])
    									  {
    										  if ([entityClassName isEqualToString:@"CommonManagedObject"]) 
    										  {
    											  NSLog(@"verify: %@",[entityDescription name]);
    										  }
    										  else 
    										  {
    #if 0 //crashes
    											  Class superClass = class_getSuperclass(NSClassFromString(entityClassName));
    											  if ([NSStringFromClass(superClass) isEqualToString:@"CommonManagedObject"]) 
    											  {
    												  NSLog(@"verify: %@",[entityDescription name]);
    											  }											  
    #endif										  
    										  }										  
    									  }					  
    								  }];
    	return result;
    }
    
     
  2. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #2
    isKindOfEntity: sounds like it should do what you want:

    Code:
    NSEntityDescription *ed = [NSEntityDescription entityForName:@"CommonManagedObject"
                                          inManagedObjectContext:model];
    		
    if ([entityDescription isKindOfEntity:ed]) {
        NSLog(@"valid");
    }
    
    
     
  3. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #3
    Thanks for the suggestion, but commonManagedObject doesn't have to be an Entity in the model and thus doesn't necessarily has an NSEntityDescription.
    BTW, you mixed up NSManagedObjectContext with NSManagedObjectModel. There is at this stage no NSManagedObjectContext yet.
     
  4. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #4
    Indeed, sorry about that. Does this do what you want?

    Code:
    [NSClassFromString(entityClassName) isSubclassOfClass:[CommonManagedObject class]]
    
     
  5. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #5
    solved

    No apology required! Yes, that does the trick! Thanks! :D
    I can't believe I missed that. :eek:

    Code:
    #define requiredAttributes [NSArray arrayWithObjects:@"title",@"noSuchAttribute",nil] //noSuchAttribute to test failure
    #define evaluateAllEntities 1
    
    @implementation CommonManagedObject
    
    #pragma mark - 
    #pragma mark framework verification
    +(void) load
    {
    	[super load];
    	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];	
    	NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    	if (![CommonManagedObject verifyManagedObjectModel:model])
    		NSLog(@"Incorrect use of framework. NSManagedObjectModel does not adhere to requirements for CommonManagedObject");
    	[pool release];
    }
    
    +(BOOL) verifyManagedObjectModel:(NSManagedObjectModel *) model
    {	
            __block BOOL result = TRUE;
    	NSArray *allEntities = [model entities];
    	[allEntities enumerateObjectsWithOptions:NSEnumerationConcurrent 
    								  usingBlock:^(id entityDescription, NSUInteger idx, BOOL *stop) {
    									  NSString *entityClassName = [(NSEntityDescription *)entityDescription managedObjectClassName];  
    									  if ( ![entityClassName isEqualToString:@"NSManagedObject"]
    										  &&
    										#if evaluateAllEntities 
    										  //evaluate all Entities evaluateAllEntities
    										   ([NSClassFromString(entityClassName) isSubclassOfClass:[CommonManagedObject class]]) 
    										#endif
    										#if !evaluateAllEntities  
    										  //evaluate only Entities with CommonManagedObject as class or superclass
    										  ([entityClassName isEqualToString:@"CommonManagedObject"] || ( [NSClassFromString(entityClassName) superclass] == [CommonManagedObject class])) 										  
    										#endif  
    										  )
    									  { 
    										  NSArray *allAttributes = [[entityDescription attributesByName] allKeys];											  
    										  for (NSString *requiredAttribute in requiredAttributes)
    										  {
    											  if (![allAttributes containsObject:requiredAttribute]) 
    											  {
    												  NSLog(@"\"%@\" failed for attribute \"%@\"",[entityDescription name],requiredAttribute);  
    												  result = FALSE;
    												  *stop = TRUE;
    											  } 
    										  }										  
    									  }					  
    								  }];
    	return result;
    }
    
    
     

Share This Page