Converting ManagedObject to NSObject - iphone

I am trying to get the data from 'Employee' Entity which has empId, Name, deptId as attributes.
// Used to Populate data in table
Employee : NSObject
#property (nonatomic, retain) NSString *name;
#property int empId;
#property int deptId;
#synthesize empId, name, deptId;
&
CDEmployee : NSManagedObject
#property (nonatomic, retain) NSString *name;
#property int empId;
#property int deptId;
- (void)convertMyData:(Employee *)emp;
#dynamic empId, name, deptId;
- (void)convertMyData:(Employee *)emp
{
self.empId = emp.empId;
self.name = emp.name;
self.deptId = emp.deptId;
}
// My code to fetch & convert data retured from db to Employee class
-(NSArray *)getAllEmployees:(NSManagedObjectContext*)context
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(empId > %#)",[NSNumber numberWithInt:-1],[NSNumber numberWithInt:1]];
NSFetchRequest* req = [self createRequest:context]; // Request is correct
[req setPredicate:predicate];
NSFetchedResultsController* fetchContr = [[NSFetchedResultsController alloc] initWithFetchRequest:req managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
NSError* error = nil;
[fetchContr performFetch:&error];
NSArray *fetchedObjects = [fetchContr fetchedObjects];
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
for(int i = 0; i < [fetchedObjects count]; i++)
{
CDEmployee *cdEmp = [[fetchedObjects objectAtIndex:i] retain]; // just tried retaing
if (cdEmp)
{
Employee *emp = [[Employee alloc] init];
NSLog(#"Employee - %#", emp); // Shows tht is has object
[cdEmp convertMyData:emp]; //-----> Crashing here
[result addObject:emp];
[emp release];
}
}
[fetchContr release];
return result;
}
I am fetching results from core data & I am getting correct results back, but when I convert my core data result back to Employee(NSObject) class i am getting [NSManagedObject convertMyData:]: unrecognized selector sent to instance.
I tried adding another method say -(void)helloWorld to CDEmployee class & tried [cdEmp helloWorld]; but got the same crash.
Not getting why its causing the problem. I have method defined & implemented at proper place & its not even giving warning to me at compile time.

Here is a sample code that converts NSManagedObject to NSDictionary.
NSDictionary is even more easier to handle and operate on the data than NSObject. Also refer this Git Library for other similar iOS utility class methods.
+(NSDictionary *)convertManagedObjectToDictionary:(NSManagedObject *)managedObject{
if (!managedObject){
NSLog(#"Managed object is nil");
return nil;
}
else{
unsigned int objectsCount;
objc_property_t *objectProperties = class_copyPropertyList([managedObject class], &objectsCount);
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for(int i = 0; i < objectsCount; i++) {
objc_property_t property = objectProperties[i];
NSString *name = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
id object = [managedObject valueForKey:name];
[dictionary setObject:((object == nil) ? [NSNull null] : object) forKey:name];
}
free(objectProperties);
return dictionary;
}
}

I tried in different way & got resolved http://www.raywenderlich.com/934/core-data-tutorial-for-ios-getting-started

First, you should really first think about what you want to accomplish from a non-technical perspective. What is it, actually?
Second, NSManagedObject is a subclass of NSObject, which means you already have a NSObject. Congratulations, you are done!
Also, in your code you call fetchMyData but did not show us where you define it or what the code looks like. Maybe a NSManagedObject category would be in order here? But still, this begs the question why you would want to do this. Even if you were to convert into a Foundation object, such as NSDictionary as suggested in the other answer, you would still have a problem with modelling relationships...
Finally, what SDK are you using? You can't be serious if you are still not using ARC.

Related

How to sort NSMutableArray of object in ascending or descending order

I have created an NSMutableArray of Object using this code
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray * ary1 = [NSArray arrayWithObjects:#"01/07",#"02/07",#"03/07",#"04/07",#"05/07",#"06/07",#"07/07", nil];
NSArray * ary2 = [NSArray arrayWithObjects:#"First",#"Second",#"Third",#"Forth",#"Fifth",#"Sixth",#"Seventh", nil];
NSArray * ary3 = [NSArray arrayWithObjects:#"1000",#"2000",#"3000",#"4000",#"5000",#"6000",#"7000", nil];
tableAry = [[NSMutableArray alloc] init];
for (int i=0; i<ary1.count; i++) {
//cardSummry will hold the data and give back the model to store in array and we can find that value using model
DataModel *dataModel = [[DataModel alloc] init];
dataModel.date = [ary1 objectAtIndex:i];
dataModel.name = [ary2 objectAtIndex:i];
dataModel.ammount = [ary3 objectAtIndex:i];
[tableAry addObject:dataModel];
}
}
And this is my DataModel Class
.H file
#import <Foundation/Foundation.h>
#interface DataModel : NSObject
//this variable is used to get the data from array
#property (nonatomic,strong) NSString *date;
#property (nonatomic,strong) NSString *name;
#property (nonatomic,strong) NSString *ammount;
//this method will genarate a data model which will be added to array for future use
+ (id)cardSummary:(NSString*)date name:(NSString*)name ammount:(NSString*)ammount;
#end
.M file
#import "DataModel.h"
#implementation DataModel
#synthesize date,name,ammount;
//this method will genarate a data model which will be added to array for future use
+ (id)cardSummary:(NSString*)date name:(NSString*)name ammount:(NSString*)ammount
{
DataModel *dataModel = [[self alloc] init];
[dataModel setDate:date];
[dataModel setAmmount:ammount];
[dataModel setName:name];
return dataModel;
}
#end
Now i want to sort it according to the name in that array i have seen this Question in SO which look like mine and use its answer code to solve my problem but it didn't work for me which is this
[tableAry sortUsingDescriptors:
[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)]]];
NSLog(#"tableAry : %#",tableAry);
So how can i sort my array
Update
As #Martin R And #Rick said i have alloc my array but now i got this error.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[DataModel caseInsensitiveCompare:]: unrecognized selector sent to instance 0x7550850'
You can also use the NSSortDescriptor.
NSSortDescriptor* sortDes = [[NSSortDescriptor alloc] initWithKey:#"your key" ascending:YES];
[_array sortUsingDescriptors:[NSArray arrayWithObject:sortDes]];
Try it.
[tableAry sortUsingComparator:^NSComparisonResult(DataModel *obj1, DataModel *obj2) {
return [obj1.name caseInsensitiveCompare:obj2.name];
}];
-(NSMutableArray*)sortArrayInAssendingOrder:(NSMutableArray*)array{ // array must have numerical value
NSMutableArray *newArray=[NSMutableArray arrayWithArray: array];
NSMutableArray *shortedArray=[[NSMutableArray alloc]init];
for (int i=0; i<=[newArray count]+1; i++) {
NSInteger value_1=[[newArray objectAtIndex:0]integerValue];
for(int j=0; j<[newArray count]; j++){
NSInteger value_2=[[newArray objectAtIndex:j]integerValue];
if(value_1>value_2){
value_1 =nil;
value_1 = value_2;
}
}
[shortedArray addObject:value_1];
[newArray removeObject: value_1];
}
[shortedArray addObject:[newArray objectAtIndex:0]];
return shortedArray;
}
-(NSMutableArray*)shortCardInAssendingOrder:(NSMutableArray*)cardSetArr{
NSMutableArray *shortedArray=[[NSMutableArray alloc]init];
for (int i=0; i<=[cardSetArr count]+1; i++) {
Card *firstCard=[cardSetArr objectAtIndex:0];
for(int j=0; j<[cardSetArr count]; j++){
Card *nextCard=[cardSetArr objectAtIndex:j];
if(firstCard.cardSymbol>nextCard.cardSymbol){
firstCard=nil;
firstCard=nextCard;
}
}
[shortedArray addObject:firstCard];
[cardSetArr removeObject:firstCard];
}
[shortedArray addObject:[cardSetArr objectAtIndex:0]];
return shortedArray;
}
Note: you can use ur tag or any thing else at tha place of cardSymbol

ordering NSString of NSArray in a particular order

I have a NSString in an NSArray and I wanted to order this string/fields based on how important it is. So say the string is B, H, A, Q, Z, L, M, O.
I wanted it to be always sorted as A, Q, Z, B, H, O, L, M. This is a predefined set of rule. How do I do this? Can this be done using NSSortDescriptor?
The short answer: Yes!
And here's how...
Since there are two pieces of information you need to know about your value (the importance and the value itself), you should create an object with these two important pieces of information, then store in an array similar to the way you store your strings. This makes it simple if, say, you want to change the 'importance' some time later with very little effort:
#interface MyObject : NSObject
#property (nonatomic, readwrite) NSInteger sortOrder;
#property (nonatomic, retain) NSString *value;
#end
#implementation MyObject
#synthesize sortOrder;
#synthesize value;
-(NSString *)description
{
//...so I can see the values in console should I NSLog() it
return [NSString stringWithFormat:#"sortOrder=%i, value=%#", self.sortOrder, self.value];
}
-(void)dealloc
{
self.value = nil;
[super dealloc];
}
#end
Add your objects to an array. Then sort:
NSMutableArray *myArrayOfObjects = [NSMutableArray array];
//Add your objects
MyObject *obj = [[[MyObject alloc] init] autorelease];
obj.sortOrder = 1;
obj.value = #"A";
[myArrayOfObjects addObject:obj];
obj = [[[MyObject alloc] init] autorelease];
obj.sortOrder = 2;
obj.value = #"Q";
[myArrayOfObjects addObject:obj];
//Sort the objects according to importance (sortOrder in this case)
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES] autorelease];
NSArray *sortedArray = [myArrayOfObjects sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSLog(sortedArray); //<--See for yourself that they are sorted
NSArray has several sort functions. Three you might consider are:
- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr
- (NSArray *)sortedArrayUsingSelector:(SEL)comparator
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context
I think you might find the second, selector-based comparator the easiest to use to get started. See the docs here:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html#//apple_ref/occ/instm/NSArray/sortedArrayUsingSelector:
EDIT:
I think using NSSortDescriptor may be overkill, but here is a good post describing it:
How to sort NSMutableArray using sortedArrayUsingDescriptors?

Message Sent to Deallocated Instance

I'm using TouchXML to parse an element in iOS. I retrieve a response from a web service using an NSInvocationOperation, then parse and display the results. Everything works fine as the background thread displays results on the main thread using [self performSelectorOnMainThread:#selector(displayLoginresult:) withObject:res waitUntilDone:NO]; but then I get an error:
2011-07-18 11:58:06.108 billsApp[873:7107] *** -[CFString release]: message sent to deallocated instance 0x5d809b0
The code to parse the element is:
-(LoginResult *) tryLogin:(NSString *)userName withPassword:(NSString*)password{
NSURL *url = [UrlUtility TryLogin:userName passwordHash:password];
CXMLDocument *responseObj = [UrlUtility xmlDocWithUrl:url];
if(responseObj == [NSNull null])
return [NSNull null];
CXMLElement *eleUser = [responseObj nodeForXPath:#"//User" error:nil];
CXMLElement *eleResult = [responseObj nodeForXPath:#"//Result" error:nil];
LoginResultType resultType;
//NSLog(#"Result: ");
//NSLog(eleResult );
// NSLog([[eleResult stringValue] lowercaseString]);
if ([[[eleResult stringValue] lowercaseString ] isEqualToString: #"successful"]){
resultType = Successful;
} else {
resultType = InvalidUsernameOrPassword;
}
LoginResult *res = [[LoginResult alloc] init];
res.result = resultType;
for (CXMLElement *resultElement in [responseObj children] ) {
NSLog([NSString stringWithFormat:#"%# %#", [resultElement name], [resultElement stringValue]]);
}
//todo: fix enum parsing =[LoginResult loginResultTypeStringToEnum: [eleResult stringValue]];
if(eleUser != nil) {
CXMLElement *eleClientID = [eleUser nodeForXPath:#"ClientID" error:nil];
CXMLElement *eleCompanyName = [eleUser nodeForXPath:#"CompanyName" error:nil];
CXMLElement *eleCompanyContact = [eleUser nodeForXPath:#"CompanyContact" error:nil];
CXMLElement *eleIsAgent = [eleUser nodeForXPath:#"IsAgent" error:nil];
CXMLElement *eleParentID = [eleUser nodeForXPath:#"ParentID" error:nil];
NSInteger *clientId = [[eleClientID stringValue] integerValue];
NSString *companyName = [eleCompanyName stringValue];
NSString *companyContact = [eleCompanyContact stringValue];
bool isAgent = [Utils stringToBool:[eleIsAgent stringValue]];
NSInteger *parentId = [[eleParentID stringValue] integerValue];
User *user = [[User alloc] initWithData:clientId companyName:companyName companyContact:companyContact isAgent:isAgent parentId:parentId];
res.user = user;
// release elements
// [eleClientID release];
// [eleCompanyName release];
// [eleCompanyContact release];
// [eleIsAgent release];
// [eleParentID release];
//release raw values
// [companyName release];
// [companyContact release];
}
// [eleResult release];
// [eleUser release];
return res;
}
Part of me wants to say it's a bug with TouchXML, but I find that very unlikely. Is there any way to further track down the error?
EDIT: The definitions for the properties on the User class is:
#property (nonatomic, readwrite) NSInteger clientId;
#property (nonatomic, retain) NSString *companyName;
#property (nonatomic, retain) NSString *companyContact;
#property (nonatomic, readwrite) bool isAgent;
#property (nonatomic, readwrite) NSInteger parentId;
And the instance is initialized with:
-(User*)initWithData:(NSInteger *)clientId companyName:(NSString *)company companyContact:(NSString*)contact isAgent:(bool)agent parentId:(NSInteger*)parentId {
//[self = super init];
self.clientId= clientId;
self.companyName= company;
self.companyContact= contact;
self.isAgent = agent;
self.parentId = parentId;
return self;
}
And the LoginResult class is:
#interface LoginResult : NSObject {
LoginResultType result;
User *user;
NSString * const loginResultTypeArray[4];
}
#property (nonatomic, readwrite) LoginResultType result;
#property (nonatomic, retain) User *user;
Just a try: are you correctly retaining companyName and companyContatct in your User class?
EDIT:
Next thing I would check is loginResultTypeArray. How are string assigned to it? I guess that this advice will also sound trivial to you, but it is really difficult to come up with useful suggestion with so little code...
Can't you get some idea about which CFString is actually being released? If it is not an autoreleased object, possibly the stack trace could point at the method which is sending the release message... this would be very helpful...
Otherwise, I would try and NSLog some of your NSStrings addresses, so that you can compare them with the address you find in the error log (and, again, try and find out which string was actually reused after deallocation).
Finally, another approach to find out which string is used after deletion could be using method swizzling to replace NSString's dealloc with a method of yours that, before calling the swizzled dealloc, does some logging of the objec. This will produce much log info, but knowing the address of the string you could find easily what you need. Find here info about swizzling.
This was a nightmare to track down. I had a method which returned an NSString *, which was then parsed by another method to produce an XML document, then release by the second method. I actually needed to autorelease it in the first method.

Compare string to NSArray

I have to classes the Checkin and the FriendList.
Checkin.h
#interface Checkin : NSObject {
NSString *name;
NSString *profID;
NSString *place;
NSString *photoURL;
NSMutableArray *taggedID;
NSMutableArray *taggedName;
and the Friendlist.h
#interface FriendList : NSObject {
NSString *name;
NSString *profID;
}
What I am trying to do is to compare each checkin.profid(approximately 5-6) with the friendlist.h(200-5000).
I tried to do it with for loop but when checks the second checkin.profid is crashing.
This is my method:
for(int i=0; i<[checkinArray count];i++){
Checkin *tempcheck = [[Checkin alloc] init];
tempcheck = [checkinArray objectAtIndex:i];
for(int j=0;j<[friendsArray count]; j++){
NSLog(#"count %d",j);
FriendList *tempfriend = [[FriendList alloc] init];
tempfriend = [friendsArray objectAtIndex:j];
if([tempcheck.profID isEqualToString:tempfriend.profID]){
NSLog(#"Find prof id same for : %#",tempcheck.name);
break;
}
else
NSLog(#"Not found id same for: %#",tempcheck.name);
[tempfriend release];
}
[tempcheck release];
}
}
Is there any better way to do this comparison? Because its also too slow.
Thank you in advance
this isn't going to be helping:
Checkin *tempcheck = [[Checkin alloc] init];
tempcheck = [checkinArray objectAtIndex:i];
And
FriendList *tempfriend = [[FriendList alloc] init];
tempfriend = [friendsArray objectAtIndex:j];
there's no reason to alloc them: just set it to be the object at the desired index:
Checkin *tempcheck = [checkinArray objectAtIndex:i];
would be better. As for doing the finds, why not loop through the checkins and for each checkin.profId instantiate a new NSPredicate to find the profId through the friendlist. Try [NSPredicate filterWithFormat:#"(profId = %#)"];
and then use filteredArrayUsingPredicate on your array.
Your memory management is all broken. When you do something like this:
Checkin *tempcheck = [[Checkin alloc] init];
tempcheck = [checkinArray objectAtIndex:i];
What you are doing is creating an object and then assigning the pointer to the object in the checkin array. This causes a memory leak right there.
Then, later on when you do:
[tempcheck release];
you're actaully calling release on the object in the array, not the one you alloc'd earlier. This presumably leads the the object in the array being garbage-collected and then when you try and access it the second time round you get a crash.
Remove the allocs & releases and just do something like this:
Checkin *tempcheck = [checkinArray objectAtIndex:i];

Filling class variables from an NSDictionary in a loop

I would like to fill in the class variables in a loop from an dictionary. What I want to do is having the dictionary key as a class variable and assign the class variable (the dictionary key) the value from dictionary... something like this:
+(void) initWithDictionary:(NSDictionary *)dic {
MyClass *classInstance = [[[self alloc] init] autorelease];
NSArray *allKeys = [dic allKeys];
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
id classVariable = [allKeys objectAtIndex:i];
classInstance.classVariable = [dic objectForKey:[allKeys objectAtIndex:i]];
}
return classInstance;
}
It does not work, because I do not know how to assign the class variable from the string.
Thanks for answer, I am returning a JSON string that gives me an NSDictionary with keys and values. I am trying to fill this values to my class, let's say DetailObject. I want to use later in the project the DetailObject.id, DetailObject.description, etc. I would like to do it in a loop, becouse now I have to write this:
+ (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
DetailObject *classInstance = [[[self alloc] init] autorelease];
classInstance.id = [dic objectForKey#"id"];
classInstance.desc = [dic objectForKey#"desc"];
etc... etc...
return classInstance;
}
What I want is to parse the dictionary from JSON to my object and respective variables and values that comes from dictionary in a loop, because if the JSON dictionary changes, I just add the new class variable with the same name of the returned dictionary key...
I do not know if I have explained it well...
Your question is very very unclear and I have no idea what you're trying to do or why. But just looking at your code I can tell you already that it's definitely not doing what you want.
//There should be no semicolon after "dic" below.
//Also, you should be returning a MyClass or an id.
- (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
MyClass *classInstance = [[[self alloc] init] autorelease];
//Getting all the keys from the dictionary, seems fine...
NSArray *allKeys = [dic allKeys];
//Looping through all the keys in the dictionary, seems okay...
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
//Storing the current key.
id classVariable = [allKeys objectAtIndex:i];
//Assigning the class's property "classVariable" to match the current key's value.
//No reason to say "[allKeys objectAtIndex:i]" again, though.
classInstance.classVariable = [dic objectForKey:classVariable];
}
//Returning something when you have no return type above (void) is wrong.
return classInstance;
}
Your code will just assign classInstance.classVariable to be equal to [allKeys objectAtIndex:[allKeys count]-1]. Your loop is pointless.
After I actually annotated your code though I think I have some idea of what you want. Basically you want to assign the variables with names matching the keys in the dictionary the values in the dictionary. i.e. if there is a key called "superKey" then you want to find the variable within classInstance (classInstance.superKey) and assign it the value in the dictionary that matches superKey. That's what you want, right?
Well, the only way I know of to do that is to use a big switch statement or a bunch of if statements. Make some function within MyClass like this:
- (void) assignProperty:(id)property toValue:(id)value
{
if (property == #"superKey")
{
self.superKey = value;
}
else if (property == #"lameKey")
{
self.lameKey = value;
}
//etc.
}
Then you just call [classInstance assignProperty:classVariable toValue:[doc objectForKey:classVariable]] and the job will be done.
But having told you all that...
Why would you ever want to do what you're doing? Want to know a much better way of doing this? Give MyClass its own NSDictionary. Basically all you are doing is defeating the entire purpose of the dictionary. Why? They are incredibly fast to access and can store whatever you want. There is no reason not to use one. So just do this:
- (id) initWithDiccionary :(NSDictionary *)dic
{
MyClass *classInstance = [[[self alloc] init] autorelease];
classInstance.dictionary = dic;
return classInstance;
}
Voila.
Enter Key-Value Coding. The following is an example of how you could achieve your desired outcome:
#interface MyClass : NSObject
#property (nonatomic, retain) NSString *aString;
#property (nonatomic, retain) NSNumber *aNumber;
#property (nonatomic, retain) NSString *yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary;
#end
#implementation MyClass
#synthesize aString;
#synthesize aNumber;
#synthesize yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary {
if ((self = [super init])) {
[self setValuesForKeysWithDictionary:dictionary];
}
return self;
}
// dealloc is left as an exercise for the reader
#end
You could use this class as follows:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"my string", #"aString",
[NSNumber numberWithInt:42], #"aNumber",
#"strings!", #"yetAnother", nil];
MyClass *myClass = [[MyClass alloc] initWithDictionary:dictionary] autorelease];
// yay!
You can thank Objective-C's dynamism for that. :)