Save a lot of code by using NSClassFromString in Objective C
2013-06-14 12:03
441 查看
Recently, I am implementing database synchronize feature by using SQL sync framework 2.1. In the iOS client, I need save each row of data (entity) into its corresponding table.
From the metadata of the response, I can see the entity table name and its columns' value and name. Usually, I need write method for each table to save the entity into the table, like below piece of code: Status and Priority are the tables' name.
// populates the StatusEntity store with the values from the json object dict
+ (void)populateStatus: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context;
{
bool isTombstone = [Utils isDeleted:metadata];
StatusEntity *status = nil;
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"Status" inManagedObjectContext:context]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"ID = %@", [dict valueForKey:@"ID"]]];
NSArray *results = [context executeFetchRequest:fetch error:nil];
if (results.count == 1)
{
status = [results objectAtIndex:0];
}
if (status == nil && !isTombstone)
{
// insert new status
status = [NSEntityDescription insertNewObjectForEntityForName:@"Status" inManagedObjectContext:context];
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && status != nil)
{
[context deleteObject:status];
}
else if (!isTombstone)
{
status.ID = [dict valueForKey:@"ID"];
status.statusName = [dict valueForKey:@"Name"];
}
}
// populates the PriorityEntity store with the values from the json object dict
+ (void)populatePriority: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context;
{
bool isTombstone = [Utils isDeleted:metadata];
PriorityEntity *priority = nil;
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"Priority" inManagedObjectContext:context]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"ID = %@", [dict valueForKey:@"ID"]]];
NSArray *results = [context executeFetchRequest:fetch error:nil];
if (results.count == 1)
{
priority = [results objectAtIndex:0];
}
if (priority == nil && !isTombstone)
{
// insert new status
priority = [NSEntityDescription insertNewObjectForEntityForName:@"Priority" inManagedObjectContext:context];
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && priority != nil)
{
[context deleteObject:priority];
}
else if (!isTombstone)
{
priority.ID = [dict valueForKey:@"ID"];
priority.priorityName = [dict valueForKey:@"Name"];
}
}
Thanks NSClassFromString method, which saved me a lot of time and code to just use a method to handle all the entities automatically.
The most important methods are NSClassFromString and insertNewObjectForEntityForName:
Class cls = NSClassFromString(tableName);
if (cls != Nil)
{
// if the name is a class object, then we can call the class method directly.
newObject = [cls findFirstWithPredicate:predicate];
}
and:
if (NSClassFromString(name)) {
// Based on the entity name, we can generate the entity object with below method directly. It is very helpful.
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
}
Here is the full code on my implementation, some methods are my wrapped internal method for the CoreData, which are not exposed here. But it will be very help for the reader to see how did I insert the entity :
// populates the ListEntity store with the values from the json object dict
+ (void)populateEntity: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context {
bool isTombstone = [Utils isDeleted:metadata];
NSString *uri = [metadata valueForKey:@"uri"];
NSMutableDictionary *pKeys = [NSMutableDictionary dictionary];
NSString *tableName = nil;
NSArray *sub = [uri componentsSeparatedByString:@".svc/"];
if ([sub count] == 2) {
uri = [sub objectAtIndex:1];
NSArray *subStrings = [uri componentsSeparatedByString:@"("];
if ([subStrings count] == 2) {
tableName = [subStrings objectAtIndex:0];
// (Robert #) in Heat3, the table name is capitalized. So need special convert it here.
tableName = [NSString stringWithFormat:@"%@%@",[tableName substringToIndex:1].uppercaseString, [tableName substringFromIndex:1]];
NSString *keys = [[subStrings objectAtIndex:1] stringByReplacingOccurrencesOfString:@")" withString:@""];
NSArray *subKeys = [keys componentsSeparatedByString:@","];
for (NSString *key in subKeys) {
NSArray *keyPair = [key componentsSeparatedByString:@"="];
if ([keyPair count] == 2) {
[pKeys setObject:[keyPair objectAtIndex:1] forKey: [keyPair objectAtIndex:0]];
}
}
}
} else {
NSLog(@"Something is wrong, please check.");
}
if (nil != tableName && [pKeys allKeys] > 0)
{
NSManagedObject *newObject = nil;
// measure = [TgMeasure findFirstByAttribute:@"MeasureID" withValue:[dict valueForKey:@"MeasureID"]];
if (NSClassFromString(tableName)) {
NSString *string = [NSString string];
for (NSString *key in [pKeys allKeys]) {
if ([string length] == 0) {
string = [string stringByAppendingFormat:@"%@=%@", key, [pKeys objectForKey:key]];
} else {
string = [string stringByAppendingFormat:@" and %@=%@", key, [pKeys objectForKey:key]];
}
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:string];
Class cls = NSClassFromString(tableName);
if (cls != Nil)
{
newObject = [cls findFirstWithPredicate:predicate];
}
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && newObject != nil)
{
[context deleteObject:newObject];
}
else if (!isTombstone)
{
[NSManagedObject createManagedObjectFromDictionary:dict inContext:CONTEXT_FOR_CURRENT_THREAD withName:tableName];
SAVE_COREDATA_CONTEXT;
}
}
}
+ (NSManagedObject *)createManagedObjectFromDictionary:(NSDictionary *)dictionary inContext:(NSManagedObjectContext *)context withName:(NSString *)name
{
if (NSClassFromString(name)) {
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
NSMutableDictionary *tmpDict = [NSMutableDictionary new];
for(NSString *aKey in dictionary){
id object = [dictionary valueForKey:aKey];
NSString * newKey = [aKey lowercaseString];
[tmpDict setValue:object forKey:newKey];
}
[newObject fromDictionary:tmpDict];
return newObject;
} else {
return nil;
}
}
From the metadata of the response, I can see the entity table name and its columns' value and name. Usually, I need write method for each table to save the entity into the table, like below piece of code: Status and Priority are the tables' name.
// populates the StatusEntity store with the values from the json object dict
+ (void)populateStatus: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context;
{
bool isTombstone = [Utils isDeleted:metadata];
StatusEntity *status = nil;
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"Status" inManagedObjectContext:context]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"ID = %@", [dict valueForKey:@"ID"]]];
NSArray *results = [context executeFetchRequest:fetch error:nil];
if (results.count == 1)
{
status = [results objectAtIndex:0];
}
if (status == nil && !isTombstone)
{
// insert new status
status = [NSEntityDescription insertNewObjectForEntityForName:@"Status" inManagedObjectContext:context];
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && status != nil)
{
[context deleteObject:status];
}
else if (!isTombstone)
{
status.ID = [dict valueForKey:@"ID"];
status.statusName = [dict valueForKey:@"Name"];
}
}
// populates the PriorityEntity store with the values from the json object dict
+ (void)populatePriority: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context;
{
bool isTombstone = [Utils isDeleted:metadata];
PriorityEntity *priority = nil;
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"Priority" inManagedObjectContext:context]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"ID = %@", [dict valueForKey:@"ID"]]];
NSArray *results = [context executeFetchRequest:fetch error:nil];
if (results.count == 1)
{
priority = [results objectAtIndex:0];
}
if (priority == nil && !isTombstone)
{
// insert new status
priority = [NSEntityDescription insertNewObjectForEntityForName:@"Priority" inManagedObjectContext:context];
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && priority != nil)
{
[context deleteObject:priority];
}
else if (!isTombstone)
{
priority.ID = [dict valueForKey:@"ID"];
priority.priorityName = [dict valueForKey:@"Name"];
}
}
Thanks NSClassFromString method, which saved me a lot of time and code to just use a method to handle all the entities automatically.
The most important methods are NSClassFromString and insertNewObjectForEntityForName:
Class cls = NSClassFromString(tableName);
if (cls != Nil)
{
// if the name is a class object, then we can call the class method directly.
newObject = [cls findFirstWithPredicate:predicate];
}
and:
if (NSClassFromString(name)) {
// Based on the entity name, we can generate the entity object with below method directly. It is very helpful.
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
}
Here is the full code on my implementation, some methods are my wrapped internal method for the CoreData, which are not exposed here. But it will be very help for the reader to see how did I insert the entity :
// populates the ListEntity store with the values from the json object dict
+ (void)populateEntity: (id)dict withMetadata:(id)metadata withContext:(NSManagedObjectContext*) context {
bool isTombstone = [Utils isDeleted:metadata];
NSString *uri = [metadata valueForKey:@"uri"];
NSMutableDictionary *pKeys = [NSMutableDictionary dictionary];
NSString *tableName = nil;
NSArray *sub = [uri componentsSeparatedByString:@".svc/"];
if ([sub count] == 2) {
uri = [sub objectAtIndex:1];
NSArray *subStrings = [uri componentsSeparatedByString:@"("];
if ([subStrings count] == 2) {
tableName = [subStrings objectAtIndex:0];
// (Robert #) in Heat3, the table name is capitalized. So need special convert it here.
tableName = [NSString stringWithFormat:@"%@%@",[tableName substringToIndex:1].uppercaseString, [tableName substringFromIndex:1]];
NSString *keys = [[subStrings objectAtIndex:1] stringByReplacingOccurrencesOfString:@")" withString:@""];
NSArray *subKeys = [keys componentsSeparatedByString:@","];
for (NSString *key in subKeys) {
NSArray *keyPair = [key componentsSeparatedByString:@"="];
if ([keyPair count] == 2) {
[pKeys setObject:[keyPair objectAtIndex:1] forKey: [keyPair objectAtIndex:0]];
}
}
}
} else {
NSLog(@"Something is wrong, please check.");
}
if (nil != tableName && [pKeys allKeys] > 0)
{
NSManagedObject *newObject = nil;
// measure = [TgMeasure findFirstByAttribute:@"MeasureID" withValue:[dict valueForKey:@"MeasureID"]];
if (NSClassFromString(tableName)) {
NSString *string = [NSString string];
for (NSString *key in [pKeys allKeys]) {
if ([string length] == 0) {
string = [string stringByAppendingFormat:@"%@=%@", key, [pKeys objectForKey:key]];
} else {
string = [string stringByAppendingFormat:@" and %@=%@", key, [pKeys objectForKey:key]];
}
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:string];
Class cls = NSClassFromString(tableName);
if (cls != Nil)
{
newObject = [cls findFirstWithPredicate:predicate];
}
}
// if its deleted and we have not seen it ignore it
// else delete it
if (isTombstone && newObject != nil)
{
[context deleteObject:newObject];
}
else if (!isTombstone)
{
[NSManagedObject createManagedObjectFromDictionary:dict inContext:CONTEXT_FOR_CURRENT_THREAD withName:tableName];
SAVE_COREDATA_CONTEXT;
}
}
}
+ (NSManagedObject *)createManagedObjectFromDictionary:(NSDictionary *)dictionary inContext:(NSManagedObjectContext *)context withName:(NSString *)name
{
if (NSClassFromString(name)) {
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
NSMutableDictionary *tmpDict = [NSMutableDictionary new];
for(NSString *aKey in dictionary){
id object = [dictionary valueForKey:aKey];
NSString * newKey = [aKey lowercaseString];
[tmpDict setValue:object forKey:newKey];
}
[newObject fromDictionary:tmpDict];
return newObject;
} else {
return nil;
}
}
相关文章推荐
- Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id)等NSClassFromString
- NSClassFromString,NSSelectorFromString,isKingOfClass
- New release of code samples from Microsoft All-In-One Code Framework (2011-6-19)
- stringByReplacingPercentEscapesUsingEncoding attributesOfItemAtPath
- Unable to find a value for "dwmc" in object of class "java.lang.String" using operator "." (null
- iOS---stringByAddingPercentEscapesUsingEncoding:' is deprecated: first deprecated in iOS 9.0 - Use -stringByAddingPercentEncodingWithAllowedCharacters: instead,
- NSClassFromString,NSSelectorFromString,isKingOfClass
- iOS NSClassFromString,NSSelectorFromString,isKingOfClass
- NSClassFromString,NSSelectorFromString,isKingOfClass
- 164 Using the LIST command in Recovery Manager (RMAN), which two pieces of information from the RMAN
- How can I get the IPv4 address of an interface in linux from C code ?
- LINQ Introduction Part 1 Of 3 By Sacha Barber(Refer from codeproject)
- Using LINQ Group By and String.Join() / Aggregate() in Entity Framework 3.5
- How to hide & unhide the grid from the page by using people code?
- Handle unmanaged code in managed c# with the help of using statement
- 174 Using the LIST command in Recovery Manager (RMAN), which two pieces of information from the RMAN
- NSClassFromString isKindOfClass
- 转载:Character data is represented incorrectly when the code page of the client computer differs from the code page of the database in SQL Server 2005
- Get data by SAFEARRAY** from COM(VB Code) in My VC COM Project (Code Part)
- Example Code of Using XML Parser in Symbian OS