Sort Array of NSString By Custom Method - objective-c

How would I go about sorting an array of NSString Objects by a custom method. For example I have a method
-(int)calculateValue:(NSString *)aString
I would like to sort an array by descending order based on the returned value from this method. So for example I have an array
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"Apple", #"Bee", #"Super", nil];
Now if I call calculateValue for each of those strings it might return values such as.
"Apple" = 15, "Bee" = 21, and "Super" = 3. Now I'm trying to sort that array based on the returned value for each NSString from the calculateValue method. So then the sorted array would like like
[Bee, Apple, Super]

See -sortedArrayUsingSelector:. You'll pass in a selector like #selector(myComparisonMethod:). Your comparison method should return an NSComparisonResult like NSOrderedAscending, NSOrderedDescending, or NSOrderedSame.

Related

reassigning a bool value to NSArray

i have an NSArray with bool values:
NSArray* boolResults = [super foo:values];
how can i change the value in cell 0?
i tried the following:
boolResults[0] = #NO;
this results in an error: Expected method to write array element not found on object of type 'NSArray *'
and also this:
BOOL* b = &[[array objectAtIndex:i] boolValue];
got the following error: Address expression must be an lvalue or a function designator
i don't wish to convert this NSArray to NSMutableArray in order to set this value, is there a normal way to do this?
Thanks
If the array isn't mutable, then you can't change that value. The solutions are two:
Make the array mutable;
Let the array contain mutable objects.
Since you don't want to use a mutable array, I'll make you an example with the second solution. Since there isn't a mutable number in the standard framework, I'll wrap it into NSMutableData. The example supposes that you have an array with a single object, with value #YES, and you want to change it to #NO:
NSNumber* number= #YES;
NSMutableData* data=[[NSMutableData alloc]initWithData: [NSKeyedArchiver archivedDataWithRootObject: number]];
NSArray* array= #[data]; // Now you have an array with a single value
// You want to change the first value to #NO:
number= #NO;
[array[0] setData: [NSKeyedArchiver archivedDataWithRootObject: number]];
No. NSArrays are immutable. You could reassign your pointer to the array with a modified NSArray.
NSArray *anArray = [super foo:values]
NSMutableArray *mutableCopy = [anArray mutableCopy];
// change your mutable copy and then reassign
anArray = [mutableCopy copy];
And just like NSArray, NSNumbers are also immutable, so something like [anArray[0] setBoolValue:NO] does not exist.

NSSet: return an NSArray of objects sorted by a list of strings on certain property of each object?

I have an NSSet of objects.
Each object in the set is an instance of MyObject with a property called name.
I have another NSArray called nameIndexes which contains name values.
I would like to have a function that takes the NSSet and returns a sorted array sorted using the name property based on its position in the nameIndexes array.
Edit:
Sorry for my misleading, here is an example:
I have a set of MyObject(may not be in the same order):
MyObject1 {name:#"A"}
MyObject2 {name:#"B"}
MyObject3 {name:#"C"}
I have another array of names:
{"B", "A", "C"}
I want an NSArray of:
{MyObject2, MyObject1, MyObject3}
NSSet *set = //your set.
NSArray *nameIndexes = //the array of names for sorting.
NSArray *result = [[set allObjects] sortedArrayUsingComparator:^NSComparisonResult(MyObject *obj1, MyObject *obj2) {
int index1 = [nameIndexes indexOfObject:obj1.name];
int index2 = [nameIndexes indexOfObject:obj2.name];
return [[NSNumber numberWithInt:index1] compare:[NSNumber numberWithInt:index2]];
}];
Not 100% certain what you are asking but this will sort take the set of names and turn it into a sorted array sorted based on the index of the names in a second array.
After edit
Edit... ok, so your edit completely changed the question. Anyway, from the edit you can just do...
NSArray *result = [[set allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:"name" ascending:YES]]];
This will take the set and return a sorted array sorted by the name property of the objects in alphabetical order.

Create Instance variables at runtime

I want to create instance variables dynamically at runtime, and I want to add these variables to a category. The number of the instance variables may change based on the configuration/properties file which I am using for defining them.
Any ideas??
Use Associative References - this is tricky, but that is the mechanism invented specifically for your use case.
Here is an example from the link above: first, you define a reference and add it to your object using objc_setAssociatedObject; then you can retrieve the value back by calling objc_getAssociatedObject.
static char overviewKey;
NSArray *array = [[NSArray alloc] initWithObjects:# "One", #"Two", #"Three", nil];
NSString *overview = [[NSString alloc] initWithFormat:#"%#", #"First three numbers"];
objc_setAssociatedObject (
array,
&overviewKey,
overview,
OBJC_ASSOCIATION_RETAIN
);
[overview release];
NSString *associatedObject = (NSString *) objc_getAssociatedObject (array, &overviewKey);
NSLog(#"associatedObject: %#", associatedObject);
objc_setAssociatedObject (
array,
&overviewKey,
nil,
OBJC_ASSOCIATION_ASSIGN
);
[array release];
I'd be inclined to just use a NSMutableDictionary (see NSMutableDictionary Class Reference). Thus, you would have an ivar:
NSMutableDictionary *dictionary;
You'd then initialize it:
dictionary = [NSMutableDictionary dictionary];
You can then save values to it dynamically in code, e.g.:
dictionary[#"name"] = #"Rob";
dictionary[#"age"] = #29;
// etc.
Or, if you are reading from a file and don't know what the names of the keys are going to be, you can do this programmatically, e.g.:
NSString *key = ... // your app will read the name of the field from the text file
id value = ... // your app will read the value of the field from the text file
dictionary[key] = value; // this saves that value for that key in the dictionary
And if you're using an older version of Xcode (before 4.5), the syntax is:
[dictionary setObject:value forKey:key];
Depends on exactly what you want to do, the question is vague but if you want to have several objects or several integers or so on, arrays are the way to go. Say you have a plist with a list of 100 numbers. You can do something sort of like this:
NSArray * array = [NSArray arrayWithContentsOfFile:filePath];
// filePath is the path to the plist file with all of the numbers stored in it as an array
That will give you an array of NSNumbers, you can then turn that into an array of just ints if you want like this;
int intArray [[array count]];
for (int i = 0; i < [array count]; i++) {
intArray[i] = [((NSNumber *)[array objectAtIndex:i]) intValue];
}
Whenever you want to get an integer from a certain position, lets say you want to look at the 5th integer, you would do this:
int myNewInt = intArray[4];
// intArray[0] is the first position so [4] would be the fifth
Just look into using a plist for pulling data, it will them be really easy to create arrays of custom objects or variables in your code by parsing the plist.

Comparing 3 arrays of various NSObject Subclasses

I have an NSDictionary which contains 3 NSArrays,
- posts
- comments
- likes.
And in each array are consistent NSObject Subclasses:
- Post
- Comment
- Like
Usually, I would just put all objects from these three arrays into one array and compare them using the same variable which they all contain, but in this case, Posts has the variable dateOfUpload and Like and Comment have the same variable, date.
How can I compare the objects from these three arrays using the variable date and dateOfUpload to create one big array of all objects in descending date?
I would make them all implement method like:
-(NSComparsionResult) compareByDate : (NSObject *) obj;
Of course you'll need to implement this in different way in each class.
Then make one big array from all the tree arrays and call
[myArray sortUsingSelector:#selector(compareByDate:)];
Another way to do this is to add all your objects in one big array and sort using a block as follows:
// Create the array with all the objects
NSMutableArray *stuff = [NSMutableArray arrayWithArray:posts.allValues];
[stuff addObjectsFromArray:comments.allValues];
[stuff addObjectsFromArray:likes.allValues];
// Sort it by using a block
NSArray *sortedStuff = [stuff sortedArrayUsingComparator:^(id obj1, id obj2) {
NSDate *date1 = [obj1 respondsToSelector:#selector(date)]? [obj1 date] : [obj1 dateOfUpload];
NSDate *date2 = [obj2 respondsToSelector:#selector(date)]? [obj2 date] : [obj2 dateOfUpload];
return [date2 compare:date1]; // Objects are reversed to get descending order
}];

Get NSArray index number

self.listData = [NSArray arrayWithObjects:#"A",#"B",#"C", nil];
How can I get index numbers for listData items?
This code below is used to get listData items string:
c = [NSString stringWithFormat:#"%#",[listData objectAtIndex:indexPath.row];
Any idea?
Thanks
Something like...
NSUInteger index = [listData indexOfObject:#"A"];
From the docs:
Return Value
The lowest index whose
corresponding array value is equal to
anObject. If none of the objects in
the array is equal to anObject,
returns NSNotFound.
Discussion
Objects are considered
equal if isEqual: returns YES.
** Important: If anObject is nil an exception is raised.**
If you can guarantee that the strings in your array are unique, then using indexOfObject: will work. Otherwise, you'll need to use one of the indexesOfObjects* methods such as indexesOfObjectsWithOptions:passingTest: to get a set of all of the indexes containing the object you're interested in.