How to sort NSMutableArray of object in ascending or descending order - iphone

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

Related

Converting ManagedObject to NSObject

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.

Adding values to two different NSMutableArray without increasing the retain count

I have two simple NSMutableArray that consists of few objects. Some of these objects can be common but need to be stored in both of the arrays as uses of both arrays are defined for totally different purpose.
However, the problem is that after adding same objects to both array, on changing the value of one of the common object, does not reflect in 2nd array.
For example,
Let's say we have two mutable NSArray:
NSMutableArray *mutableArrayOne;
NSMutableArray *mutableArrayTwo;
Now let's create the object definition that these array needs to contain.
#interface: DummyObject : NSObject
{
int objectValue;
}
#property (nonatomic) int objectValue;
-(void) printObjectValue;
#end
Now let's create the base class to store the arrays.
Base Class Definition
#interface: BaseClass : NSObject
{
NSMutableArray *mutableArrayOne;
NSMutableArray *mutableArrayTwo;
}
-(void) init;
-(void) printBothArrays;
#end
Base Class Implementation
#implementation BaseClass
-(void) init
{
// initialize the mutable array.
mutableArrayOne = [[NSMutableArray alloc] initWithCapicity:5];
mutableArrayTwo = [[NSMutableArray alloc] initWithCapicity:5];
DummyObject *dummyObject = [DummyObject alloc];
[dummyObject setObjectValue:5];
DummyObject *dummyObjectTwo = [DummyObject alloc];
[dummyObjectTwo setObjectValue:2];
[mutableArrayOne addObject:dummyObject];
[mutableArrayOne addObject:dummyObjectTwo];
[mutableArrayTwo addObject:dummyObjectTwo];
}
#end
Now let me the modify the DummyObject in array One:
for (DummyObject* dummyObject in mutableArrayOne)
{
[dummyObject setValue:100];
}
Problem
Now here starts the problem when I am printing the values for both array objects:-
Printing First Array
for (DummyObject* dummyObject in mutableArrayOne)
{
[dummyObject printObjectValue];
}
*Output Log (from first array) *
100
100
Printing second Array
for (DummyObject* dummyObject in mutableArrayTwo)
{
[dummyObject printObjectValue];
}
*Output Log (from second array) *
2
So here we can see that MutableArray is keeping the copy of the object, however, I want to store only the reference. That means, on changing the value of the object in 1st array should reflect in 2nd array.
How can we do that?
Do we any other alternative?
Thanks,
Paras Mendiratta
This will ideally work, seems like some issue with setting object.
For e.g. you can check like this -
NSMutableString *firstString = [[NSMutableString alloc] initWithString:#"first"];
NSMutableString *secondString = [[NSMutableString alloc] initWithString:#"second"];
NSMutableArray *originalArray = [[NSMutableArray alloc] initWithObjects: firstString, secondString, nil];
NSMutableArray *copyArray = [[NSMutableArray alloc] initWithObjects: firstString, secondString, nil];
[[copyArray objectAtIndex:0] appendString:#"add some text"];
for (int index = 0; index < [originalArray count]; index++) {
NSLog(#"Original:%# --- copy:%#", [originalArray objectAtIndex:index], [copyArray objectAtIndex:index]);
}
And output is -
2012-05-09 10:28:40.382 Demo[5237:f803] Original:firstadd some text --- copy:firstadd some text
2012-05-09 10:28:40.384 Demo[5237:f803] Original:second --- copy:second
EDIT - (Not adding object at the time of initialization)
NSMutableString *firstString = [[NSMutableString alloc] initWithString:#"first"];
NSMutableString *secondString = [[NSMutableString alloc] initWithString:#"second"];
NSMutableArray *originalArray = [[NSMutableArray alloc] init];
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
[originalArray addObject:firstString];
[copyArray addObject:firstString];
[originalArray addObject:secondString];
[copyArray addObject:secondString];
[[copyArray objectAtIndex:0] appendString:#"add some text"];
for (int index = 0; index < [originalArray count]; index++) {
NSLog(#"Original:%# --- copy:%#", [originalArray objectAtIndex:index], [copyArray objectAtIndex:index]);
}
Output -
2012-05-09 11:11:18.275 Demo[5433:f803] Original:firstadd some text --- copy:firstadd some text
2012-05-09 11:11:18.277 Demo[5433:f803] Original:second --- copy:second

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];

How to create Array of Array in iPhone?

I want to create a nested array or multidimensional array.
In my data is,
FirstName class year dept lastName
Bob MBA 2000 Comp Smith
Jack MS 2001 Comp McDonald
NSMutableArray *section = [[NSMutableArray alloc] init];
I want to put my data into the section Array.
Eg:
section[0] = [FirstName,LastName];
section[1] = [class, year, dept];
So how can i put the values into array like that.
Please help me out.
Thanks
I would recommend creating a custom data storage class. You could call it PDPerson.h You'll also need the .m file. For each property, do something like this:
In the .h: Declare each of your properties like so:
#interface PDPerson : NSObject{
}
#property(nonatomic, retain) NSString *firstName;
#property(nonatomic, retain) NSString *lastName;
#property(nonatomic, retain) NSString *class;//May want to consider renaming
#property(nonatomic, retain) NSString *year;
#property(nonatomic, retain) NSString *dept;
#end
Then in the .m:
#implementation
#synthesize firstName, lastName;
#synthesize class, year dept;
-(void)dealloc{
[firstName release];
[lastName release];
[class release];
[year release];
[dept release];
}
Each time you want to create a new "Person" in your array, do this:
PDPerson *person = [[PDPerson alloc]init];
You can then easily set the properties of the object like so:
person.firstName = #"John";
person.lastName = #"Smith";
person.class = #"Math";
person.year = #"1995";
person.dept = #"Sciences";
And retrieve them:
firstNameLabel.text = person.firstName;
The nice thing about these objects is that all you have to do now is add the person object to your array:
NSMutableArray *personArray = [[NSMutableArray alloc] init];
[personArray addObject:person];
NSArray *section1 = [NSArray arrayWithObjects: #"1,1", #"1,2", #"1,3", nil];
NSArray *section2 = [NSArray arrayWithObjects: #"2,1", #"2,2", #"2,3", nil];
NSArray *section3 = [NSArray arrayWithObjects: #"3,1", #"3,2", #"3,3", nil];
NSArray *sections = [NSArray arrayWithObjects: section1, section2, section3, nil];
int sectionIndex = 1;
int columnIndex = 0;
id value = [[sections objectAtIndex:sectionIndex] objectAtIndex:columnIndex];
NSLog(#"%#", value); //prints "2,1"
Be warned, this isn't a flexible way of storing data. Consider using CoreData or creating your own classes to represent the data.
You can just nest multiple NSArray instances within an NSArray.
For example:
NSMutableArray* sections = [[NSMutableArray alloc] init];
for (int i = 0; i < numberOfSections; i++)
{
NSMutableArray* personsInSection = [[NSMutableArray alloc] init];
[sections insertObject:personsInSection atIndex:i];
for (int x = 0; x < numberOfPersons; x++)
{
Person* person = [[Person alloc] init];
[personsInSection insertObject:person atIndex:x];
}
}
This may seem like overkill when coming from languages such as C++ or Java, where multidimensional arrays can be created simply by using multiple sequare brackets. But this is way things are done with Objective-C and Cocoa.

Instantiating Custom Class from NSDictionary

I have a feeling that this is stupid question, but I'll ask anyway...
I have a collection of NSDictionary objects whose key/value pairs correspond to a custom class I've created, call it MyClass. Is there an easy or "best practice" method for me to basically do something like MyClass * instance = [map NSDictionary properties to MyClass ];? I have a feeling I need to do something with NSCoding or NSKeyedUnarchiver, but rather than stumble through it on my own, I figure someone out there might be able to point me in the right direction.
The -setValuesForKeysWithDictionary: method, along with -dictionaryWithValuesForKeys:, is what you want to use.
Example:
// In your custom class
+ (id)customClassWithProperties:(NSDictionary *)properties {
return [[[self alloc] initWithProperties:properties] autorelease];
}
- (id)initWithProperties:(NSDictionary *)properties {
if (self = [self init]) {
[self setValuesForKeysWithDictionary:properties];
}
return self;
}
// ...and to easily derive the dictionary
NSDictionary *properties = [anObject dictionaryWithValuesForKeys:[anObject allKeys]];
There is no allKeys on NSObject. You'll need to create an extra category on NSObject like below:
NSObject+PropertyArray.h
#interface NSObject (PropertyArray)
- (NSArray *) allKeys;
#end
NSObject+PropertyArray.m
#import <objc/runtime.h>
#implementation NSObject (PropertyArray)
- (NSArray *) allKeys {
Class clazz = [self class];
u_int count;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++) {
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
}
free(properties);
return [NSArray arrayWithArray:propertyArray];
}
#end
Example:
#import "NSObject+PropertyArray.h"
...
MyObject *obj = [[MyObject alloc] init];
obj.a = #"Hello A"; //setting some values to attributes
obj.b = #"Hello B";
//dictionaryWithValuesForKeys requires keys in NSArray. You can now
//construct such NSArray using `allKeys` from NSObject(PropertyArray) category
NSDictionary *objDict = [obj dictionaryWithValuesForKeys:[obj allKeys]];
//Resurrect MyObject from NSDictionary using setValuesForKeysWithDictionary
MyObject *objResur = [[MyObject alloc] init];
[objResur setValuesForKeysWithDictionary:objDict];
Assuming that your class conforms to the Key-Value Coding protocol, you could use the following: (defined as a category on NSDictionary for convenience):
// myNSDictionaryCategory.h:
#interface NSDictionary (myCategory)
- (void)mapPropertiesToObject:(id)instance
#end
// myNSDictionaryCategory.m:
- (void)mapPropertiesToObject:(id)instance
{
for (NSString * propertyKey in [self allKeys])
{
[instance setValue:[self objectForKey:propertyKey]
forKey:propertyKey];
}
}
And here's how you would use it:
#import "myNSDictionaryCategory.h"
//...
[someDictionary mapPropertiesToObject:someObject];
If your doing this sort of thing chances are your dealing with JSON and you should probably have a look at Mantle
https://github.com/Mantle/Mantle
You will then get a convenient method dictionaryValue
[anObject dictionaryValue];
Just add category for NSObject for getting dictionaryRepresentation from your custom objects (in my case using in JSON serialization only):
// NSObject+JSONSerialize.h
#import <Foundation/Foundation.h>
#interface NSObject(JSONSerialize)
- (NSDictionary *)dictionaryRepresentation;
#end
// NSObject+JSONSerialize.m
#import "NSObject+JSONSerialize.h"
#import <objc/runtime.h>
#implementation NSObject(JSONSerialize)
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
return [[self alloc] initWithDictionary:aDictionary];
}
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
aDictionary = [aDictionary clean];
self.isReady = NO;
for (NSString* propName in [self allPropertyNames]) {
[self setValue:aDictionary[propName] forKey:propName];
}
//You can add there some custom properties with wrong names like "id"
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
self.isReady = YES;
return self;
}
- (NSDictionary *)dictionaryRepresentation {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *propertyNames = [self allPropertyNames];
id object;
for (NSString *key in propertyNames) {
object = [self valueForKey:key];
if (object) {
[result setObject:object forKey:key];
}
}
return result;
}
- (NSArray *)allPropertyNames {
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableArray *rv = [NSMutableArray array];
unsigned i;
for (i = 0; i < count; i++) {
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
//You can add there some custom properties with wrong names like "id"
//[rv addObject:#"objectID"];
//Example use inside initWithDictionary:
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
free(properties);
return rv;
}
#end
Also, you can see that my solution will not work with custom objects with nested objects or arrays. For Arrays - just change the lines of code in dictionaryRepresentation method:
if (object) {
if ([object isKindOfClass:[NSArray class]]) {
#autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for (id item in (NSArray *)object) {
[array addObject:[item dictionaryRepresentation]];
}
[result setObject:array forKey:key];
}
} else {
[result setObject:object forKey:key];
}
}