NSMutableArray - Get Arrays Index Integer By Searching With A String - cocoa

I have been working with NSMutableArray and have had no problems retrieving an object from an array by using objectAtIndex:int. Rather then pulling an object out of the array by an integer is their a way to get the index position by searching the array with a string.
animalOptions = [[NSMutableArray alloc] init];
//Add items
[animalOptions addObject:#"Fish"];
[animalOptions addObject:#"Bear"];
[animalOptions addObject:#"Bird"];
[animalOptions addObject:#"Cow"];
[animalOptions addObject:#"Sheep"];
NSString * buttonTitle = [animalOptions objectAtIndex:1];
// RETURNS BEAR
int * objectIndex = [animalOptions object:#"Bear"];
// THIS IS WHAT I NEED HELP WITH, PULLING AN INDEX INTEGER WITH A STRING (ex: Bear)
Hopefully this makes sense, and there is an answer out there, I have been unable to research online and find anything through google or apple's class references.

You can use the indexOfObject: method from NSArray:
NSUInteger index = [animalOptions indexOfObject:#"Bear"];
If there are duplicate entries then the lowest index of that object is returned. For more information, take a look at the docs.

you can use [array indexOfObject:object] which will return the index of that object, now with the way you are wanting to do it, it might not w ork since the string you are specifing is not the actual string object in the array doing this however will def work
NSString * buttonTitle = [animalOptions objectAtIndex:1];// RETURNS BEARint
objectIndex = [animalOptions indexOfObject:buttonTitle] //this will return 1

Related

NSTreeController - Retrieving selected node

I added Book object in bookController (NSCreeController). Now i want to get stored Book object when i select the row.
- (IBAction)addClicked:(id)sender {
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
// NSTimeInterval is defined as double
NSUInteger indexArr[] = {0,0};
Book *obj = [[Book alloc] init];
NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle];
obj.title = [NSString stringWithFormat:#"New %#",dateString];
obj.filename = [NSString stringWithFormat:#"%d",arc4random()%100000];
[self.booksController insertObject:obj atArrangedObjectIndexPath:[NSIndexPath indexPathWithIndexes:indexArr length:2]];
}
I concede there perhaps could be a better solution--
I am unfamiliar with how NSTreeController works, but I looked a the class reference and noticed that it has a content property, similar to an NSArrayController (Which I am familiar with grabbing specific objects from).
I believe that if the content property is actually of type of some kind of tree data structure, my answer here probably won't work. The class reference says this about content:
The value of this property can be an array of objects, or a
single root object. The default value is nil. This property is
observable using key-value observing.
So this is what I historically have done with the expected results:
NSString *predicateString = [NSString stringWithFormat:NEVER_TRANSLATE(#"(filename == %#) AND (title == %#)"), #"FILENAME_ARGUMENT_HERE", #"TITLE_ARGUMENT_HERE"];
NSArray *matchingObjects = [[self content] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:predicateString]];
Then simply calling -objectAtIndex: will grab you your object. Note that the NSArray will be empty if the object doesn't exist, and if you have duplicate objects, there will be multiple objects in the array.
I also searched for an answer to your question, and found this SO thread:
Given model object, how to find index path in NSTreeController?
It looks pretty promising if my solution doesn't work, the author just steps through the tree and does an isEqual comparison.
If you could (if it's not too much trouble), leave a comment here to let me know what works for you, I'm actually curious :)

Filtering with NSPredicate - Data Type?

I wish to filter an array using a predicate but I'm being curved balled with the correct handling of data types.
First off, I have a list I want to filter with:
NSMutableArray *HospitalIDs = [[NSMutableArray alloc]init];
[HospitalIDs addObject: #"1"]; // Must be "id", int & NSInteger not accepted by XCode
[HospitalIDs addObject: #"2"]; // Must be "id", int & NSInteger not accepted by XCode
[HospitalIDs addObject: #"3"]; // Must be "id", int & NSInteger not accepted by XCode
Secondly, I have a list of objects that I want to filter using the array above:
(It's defined as NSMutableArray *HospitalObjects and is pre-populated with HospitalObjects)
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.HospitalID IN %#", HospitalIDs];
[HospitalObjects filterUsingPredicate:predicate];
NSLog(#"%i",[HospitalObjects count]);
//The expected result is 3, but it prints 0.
WHY?
Because by first array contains NSString values, but my HospitalObject.HospitalID is of type int.
I don't really want to change the data type of HospitalID in my object definition to NSString, but I cannot filter on integer values, what do I do?
Can I convert the data type WITHIN the predicate syntax? How?
First of all, the best way to store numbers in NSArray is to use NSNumber objects. You can simply convert a NSInteger to NSNumber using Objective-C literal syntax:
[HospitalIDs addObject: #(1)];
[HospitalIDs addObject: #(2)];
[HospitalIDs addObject: #(3)];
Then your predicate should work without any further changes.
There is a Type NSNumber that wraps ints, floats, bools, .. in a object.
NSMutableArray * hospitalIDs = [[NSMutableArray alloc] init];
[hospitalIDs addObject: #1]; // You can wrap an normal int into an NSNumber jusing #. In some siztuations you have to use #(yourOrdinaryValueTypeVariable)
[hospitalIDs addObject: #2];
[hospitalIDs addObject: #3];
By the way try to use proper naming using CamelCase:
Classes start with a upper case: SomeClassName
Objects, variables and method names with lower case: `SomeClassName* someObject;
Constants are all upper case: MY_CONSTANT

Add values to NSTableview in a way that lets me reorder them at will

I have an NSTableView and need to add values. I was thinking of doing it with a NSArrayController, but near my table there are four buttons: Move to top, Move up, Move down, Move to bottom. I must be able to reorder the entries in the table with these buttons.
The only thing I can think of is to use an array of dictionaries, where the first entry of the dictionary is the value displayed and the second entry of the dictionary is a double that is used to sort the array. If I move a value up or down, I take the sort value of the entry before and after the destination sum them, and then I divide by two.
I am not sure that the solution I was thinking of is appropriate. What would be the best approach to this scenario?
------EDIT-----
Working on it, and now I am having difficulties writing the updated "order" value into the arraycontroller. Beside that i am having trouble in actually sorting the table with the "order" column once that the value has been updated. Here is my code:
-(IBAction)singleMoveKeywordUp:(id)sender
{
NSInteger selectedRow = [singleKeywordTable selectedRow];
double firstnum;
double secondnum;
double newnum;
NSMutableDictionary *kwmutabledict = [[NSMutableDictionary alloc] init];
if (selectedRow < 2)
{
firstnum = 0;
kwmutabledict = [keywordscontroller.arrangedObjects objectAtIndex:0];
secondnum = [[kwmutabledict valueForKey:#"order"] doubleValue];
}
else
{
kwmutabledict = [keywordscontroller.arrangedObjects objectAtIndex:selectedRow-2];
firstnum = [[kwmutabledict valueForKey:#"order"] doubleValue];
kwmutabledict = [keywordscontroller.arrangedObjects objectAtIndex:selectedRow-1];
secondnum = [[kwmutabledict valueForKey:#"order"] doubleValue];
}
NSMutableDictionary *newkwmutabledict = [[NSMutableDictionary alloc] init];
newnum = (firstnum + secondnum)/2;
[newkwmutabledict setObject:[NSString stringWithFormat:#"%#",[kwmutabledict valueForKey:#"keyword"]] forKey: #"keyword"];
[newkwmutabledict setObject:[NSString stringWithFormat:#"%f",newnum] forKey: #"order"];
[keywordscontroller.arrangedObjects replaceObjectAtIndex:selectedRow withObject:newkwmutabledict] ; //<--------
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"order" ascending:YES];
[singleKeywordTable setSortDescriptors:[NSArray arrayWithObject:sort]];
}
This is failing at the row marked with an Arrow with the error message -[_NSControllerArrayProxy replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x100450520
I can't figure out whats wrong.
keywordscontroller.arrangedObjects returns (NSArray *) which is NOT mutable, and NSArray does not contain selector "replaceObjectAtIndex:withObject:". Hence the exception/error "unrecognized selector".

NSArray Sorting

I have an NSArray with values that I am pulling from an NSDictionary using a selector to sort with which has the following values:
John
Brian
Alex
....
Dave
When I use the code below, since they are being compared as strings, the list comes back with:
NSArray *array = [[[self myDictionary] allValues] sortedArrayUsingSelector:#selector(compare:)];
John
Dave
Brian
...
How can I get these values to sort correctly where they are in order 1, 2, 3, etc.? I've looked at several different examples for sorting, but have not been able to find an example like mine. I must also mention that I'm new to objective-c and iOS. Any help would be greatly appreciated.
Thanks!
I was actually able to figure out the solution. I created an NSComparisonResult block using custom logic to read the number portion off of the front of each string and then comparing them numerically:
NSComparisonResult (^sortByNumber)(id, id) = ^(id obj1, id obj2)
{
//Convert items to strings
NSString *s1 = (NSString *)obj1;
NSString *s2 = (NSString *)obj2;
//Find the period and grab the number
NSUInteger periodLoc1 = [s1 rangeOfString:#"."].location;
NSString *number1 = [s1 substringWithRange:NSMakeRange(0, periodLoc1)];
NSUInteger periodLoc2 = [s2 rangeOfString:#"."].location;
NSString *number2 = [s2 substringWithRange:NSMakeRange(0, periodLoc2)];
//Compare the numeric values of the numbers
return [number1 compare:number2 options:NSNumericSearch];
};
Then I sort my array by calling:
NSArray *array = [[[self myDictionary] allValues] sortedArrayUsingComparator:sortByNumber];

NSArray to Core Data items

I have an method that reads an xml file and stores the xml nodes at a certain XPath-path in an NSArray called *nodes. What I want to do is take each one of the items in the array and add it to a core data entity called Category with the attribute of "name".
I have tried a number of different ways of creating the entity but I'm not sure about the correct way to do this effectively. This is the code used to create the NSArray, any ideas on how to implement this? (ignore the NSError, I will fix this in the final version)
- (IBAction)readCategories:(id)sender
{
NSString *xmlString = [resultView string];
NSData *xmlData = [xmlString dataUsingEncoding: NSASCIIStringEncoding];
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithData:xmlData options:nil error:nil];
//XPath
NSError *err=nil;
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
}
EDIT - My loop code
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
int arrayCount = [nodes count];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSXMLElement *categoryEl;
NSString *new = [catArrayController newObject];
int i;
for (i = 0; i < arrayCount; i++)
{
[categoryEl = [nodes objectAtIndex:i]];
[new setValue:[categoryEl stringValue] forKey:#"name"];
[catArrayController addObject:new];
}
[pool release];
Here's how I'd write it:
for (NSXMLElement *categoryElement in nodes) {
NSManagedObject *newObject = [catArrayController newObject];
[newObject setValue:[categoryElement stringValue] forKey:#"name"];
[catArrayController addObject:newObject];
[newObject release];
}
First, I'm using the Objective-C 2.0 for-each syntax. This is simpler than using index variables. I eliminated i and arrayCount.
Next, I took out your NSAutoreleasePool. None of the objects in the loop are autoreleased, so it had no effect. (The newObject method returns a retained object which is, by convention, what methods with the word new in their name do) This is also why I release newObject after adding it to the array controller. Since I'm not going to be using it any more in this method, I need to release it.
Also, you had defined new (which I renamed newObject) as an NSString. Core Data objects are always either an instance of NSManagedObject or a subclass of NSManagedObject.
Your line [categoryEl = [nodes objectAtIndex:i]] won't compile. That's because the bracket syntax is used to send a message to an object. This is an assignment statement, so the bracket syntax is not needed here. (This line is also not necessary any more because of I've changed the loop to use the for-each syntax) But, for future reference, categoryEl = [nodes objectAtIndex:i]; would have worked.
What part are you having trouble with? There shouldn't be much more to it than looping through the array, creating a new managed object for each entry, and setting the correct attributes. You can create the managed object with NSEntityDescription's -insertNewObjectForEntityForName:inManagedObjectContext: method.

Resources