Setting an objectAtKey string from NSDictionary to an NSString in separate class - iphone

I have got information from a URL(JSON); I easily populate my tableView with the text from my dictionary [aCategory objectAtKey:#"names"] for the cell labels. Now, based on the cell name (category), I want to display another table that will ask for the last URL in order to grab the rest of the text, based on that category.
So, i want an ID which is in [aCategory objectAtKey:#"ID"] to save to a string and put in the URL in the next viewController. I am currently trying to generate it using the auto-generated set method to populate the NSString *ID in the target viewcontroller; when i call
[newView setID: [aCategory objectAtKey:#"ID"].
My new view controller's NSString ID says it is not empty, but when i try to check to see if it is indeed "1" or "2" i get something like /p2002 or something. However, in the original class, if i say cell.detailLabelText.text = [aCategory objectAtKey:#"ID"];, the labels correctly show "1" "2" "3".."14" etc....
SO, how can i get that ID from that key into my other viewcontroller class?
I Know it is a valid NSCFString cause i tested it both with isClass AND with the cell's detailLabelText.

I need more detail to be sure about this, but a couple of notes...
NSString is what is called a class cluster, which basically means it is actually a collection of several class different classes that the underlying framework switches between...this means if you are checking it with
isKindOfClass:
you might not be getting the results you are expecting. Check the documentation for isKindOfClass: in NSObject.
However, I am not sure if there is anything to worry about. The reason you are seeing something like '\p2002' (Could the first letter be a u?) could just be the current underlying representation of the string. Sometimes, when the device holds the content of the string in memory, it does not look exactly like "1" or "2". It doesn't mean that there is a problem: it just means that, a deeper level, the way the string is being held in memory is in different form. That is why your label might say "2" but the variable, when you check it in memory, looks different.
(I am guessing that, since you are handling JSON, the string is encoded in a form called UTF-8.) The point is, nothing may wrong at all.
The real question is, is your new view controller loading correctly or not? Maybe in the viewDidLoad: method of your new view controller, if you run something this line:
NSLog(#"%#", stringID);
This will print the value of stringID to the console. If this number is the same as the number of the table cell's label in the previous view controller, everything should have been passed correctly.

Related

UISearch bar in two NSMutables arrays

I see item UISearchBar search two arrays and very much items and not found solution, the problem its similar, have two NSMutablesArrays "subdetail" and "sublista" its show in Cell cell.textLabel and cell.detailTextLabel.
I try UISearchbar but i tray with NSPredicate and not run, try with NSRange and have more errors, i am desperate.PLEASE help me, any comments agree.
This its my code in Search:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSMutableDictionary *playas = [NSMutableDictionary dictionaryWithObjectsAndKeys:sublista, #"nombre", subdetail, #"localidad", nil];
[alldata addObject:playas];
for(NSDictionary *playas in alldata){
NSString *nombre = [playas objectForKey:#"nombre"];
NSRange nombreRange = [[nombre lowercaseString] rangeOfString:[searchText lowercaseString]];
if(nombreRange.location != NSNotFound)
[filteredList addObject:playas];
}
}
Add rest of code .m and .h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.m
Thanks in advance.
BEST REGARDS
Your code has a lot of issues with it. I don't know which ones are actually breaking it, but any of these issues could be causing severe problems.
First, the code sample you provided doesn't provide declarations for a lot of hte objects you're referencing. No way this could possibly compile as given. If these are properties of the view controller instance, you need to use the accessor methods -- self.alldata or [self alldata], whichever you prefer.
Second, it looks like you're just adding to these properties. If you never reset their contents, every time this method is called, you're going to increase the size of your data set -- looking at your code, possibly recursively.
Third, you try to merge the two datasets together, and then try to search through only one of them. Either don't merge, or search through both seperately and then merge the results. As it is, what you're doing won't work.
Fourth, your table view should really only be displaying one type of data, so you shouldn't need to merge.
Edit:
Based on the code samples you've provided, your entire VC is going to need restructuring. Given how much of your code is written in what appears to be spanish, I'm doing a bit of guesswork at what you're actually doing.
First off, assuming you're using a modern version of xcode, get rid of the #synthesize in the .m file (it's no longer needed anymore). That will cause every single place you're using the actual ivar instead of a proper getter to turn into an error, so you can fix them quickly. iVars will by default use a prefixed underscore of their property name, so you can still access them if you have to -- but only by explicitly accessing the ivar instead of the property.
Second, you should restructure how you handle the data. I don't know where you get your data, but it looks like the various objects are fairly consistent. You should go ahead and either create a new class to hold all the data, or just put them all into a single dictionary. At that point, the 'alldata' property should, in fact, be an array of all valid data. What you should do is then have a filtered list of data (filteredData would be a good name), and you place whatever data matches the search criteria in there. Just remember to either reload the table or update it appropriately as items move into and out of the filtered list.

dynamic Instance naming

I'm developing an iPad App and need some help.
Through a button within my App I want to create one object at a time.
So every time the button is touched one object should be created.
The problem I have is: I want to assign each object a dynamic name to identify this object.
This would be something like: form0, form1, form2, ..., formN.
This Name corresponds to an instance variable within every object.
So the form1 instance has a number attribute which is 1.
But how do I assign this form1, form2, etc. to a new instance?
I tried to initialize a new instance with the return of a method which creates the formX-String:
-(NSString*)giveMeName{
NSString* simpleName = #"form";
NSString* newName = [simpleName stringByAppendingString:[NSString stringWithFormat:#"%d", questionCounter]];
return newName;
}
where questionCounter is a variable which holds the int identifier for both formX and the instance number attribute.
But when I want to initialize a new instance with this function as name it's not working:
TSForm* [self giveMeName] = [[TSForm alloc] initWithInt:questionCounter headline:headlineText intro:introText];
Obviously I got something wrong with the inner working of Objective-C.
Please help me out.
what you're trying to do isn't really possible. One way that you could achieve the affect you're looking for is using an NSDictionary. For every TSForm object you create, you add that object to the dictionary with the key of the giveMeName return value.
So you start by creating your dictionary:
NSMutableDictionary *formDict = [[NSMutableDictionary alloc] init];
Then, every time you create an object, add it to the dictionary:
id *newTSForm = [[TSForm alloc] init]; // Or however you create a TSForm
[formDict setObject:newTSForm forKey:[newTSForm giveMeName]];
Then when you want to pull out the form you're looking for, you just ask the dictionary based on the name you provided:
[formDict valueForKey:nameOfForm]; // nameOfForm is the name provided by giveMeName
Hope this helps!
use NSMutableArray and keep adding your items there.
Even if what you are trying to do is technically possible, that's using tricsk in low-level objective-C runtime and KVC stuff and so on for nothing.
Using a simple NSMutableArray to keep track of all you instances (and using the index in the array to know which form you are dealing with) is the way to go.
I don't think you really need your unique identifier stuff for that (if so, you are probably thinking about your project the wrong way), as long as you have a way in your code to differentiate each form and manipulate them (the first form created will then be at index 0, the second at index 1… of your NSMutableDictionary)
If you really need this special unique identifier anyway for some strange reason, you can still use an NSMutableDictionary and use the unique identifier as your key of your dict and the form as the associated value. But you should probably think twice about your architecture ad the real need for this before, as it seems quite strange app architecture/design to do so based on your description of your needs in your question.
What you are looking for is some kind of variable variable, which don't really exist in objective-C.
This question (Objective C Equivalent of PHP's “Variable Variables”) has some different suggestions for getting similar results.

Class method (NSString type) called from viewcontroller returns nil?

I'm a c++ programmer new to objective-c.
I created a calculator app that is working fine using a single view. I have a Calculations class and a ViewController. Every time a button is pressed, an IBAction method in the ViewController calls methods defined in the Calculations class to handle the input and returns the output as an NSString which I then set as the value of the label.text field.
Now I am working on a tab bar app using the same Calculations class. This app has two tabs, each with a unique set of input buttons for the calculator (both views sharing the same input/output data). The first tab is identical to my first app with the single view, so I am trying to do this in a similar fashion.
Here is the problem:
When a button is pressed, the IBAction method that handles the input runs through the calls to the Calculations class methods (shown below) without error:
-(IBAction)readInput:(id)sender {
[_calculations input:[sender titleForState:UIControlStateNormal]];
inputField.text = [_calculations inputDisplay];
outputField.text = [_calculations outputDisplay];
}
however, both the inputDisplay and outputDisplay methods return nil. Using the debugger I noticed that I am unable to "step into" the calls to _calculations methods, instead the line is skipped and the value returned by both is nil. I added the following method:
-(IBAction)setNumber:(id)sender {
NSString *button =(NSString *)[sender titleForState:UIControlStateNormal];
inputField.text = button;
}
and if I attach this to the input buttons I can see the display updated. This seems to be an issue with calling the _calculations member functions and tab bar views (because this issue is not present using a single view).
I realize that I left out a lot of information, but I did it to avoid providing irrelevant information. I will provide all details that are necessary if asked.
Check to make sure _calculations is not nil.
You can send any message (call any method) on nil and it will just return nil, not cause an exception.
Without seeing more code it is going to be a bit difficult to diagnose.
If I was trying to debug this issue I would first make sure _calculations points to the object you want it to point to. If its loaded from a NIB then it might not be getting initialised, and still be nil. You can send messages to nil objects without any issues. If an object receives a message that it cant handle (the method doesn't exist, or the target object is nil) then the return for that call will be nil.
I have in the past put initilization code into the init: method, and spent a few hours why it wasn't being called, until it dawned on me that I needed to put my init code into the viewDidLoad:, or the initWithNibName:bundle: or even the initWithCoder: selector.
HTH, Matt

Objective C Object Functioning & Passing Arrays

I apologise if this has been asked before but I can't find the info I need.
Basically I want a UITableView to be populated using info from a server, similar to the SeismicXML example. I have the parser as a separate object, is it correct to alloc, init an instance of that parser & then tell RootViewController to make it's table data source a copy of the parser's array.
I can't include code because I haven't written anything yet, I'm just trying to get the design right before I start. Perhaps something like:
xmlParser = [[XMLParser alloc] init];
[xmlParser getXMLData];
// Assuming xmlParser stores results in an array called returnedArray
self.tableDataSource = xmlParser.returnedArray
Is this the best way of doing it?
No, you don't want to do this. You don't want your view controller directly accessing the array of the data-model. This would work in the technical sense but it would be fragile and likely to fail as the project scaled.
As the projects grow in complexity, you will want to increasingly wrap your data model object (in this case the xmlParser) in protective layers of methods to control and verify how the data model changes. Eventually, you will have projects with multiple views, multiple view controllers as well as information entering from both the user and URLs. You need to get into the habit of using the data-model object not just a dumb store you dump stuff into but as an active manager and verifier of your data.
In a situation like this I would have my data-model's array completely wrapped by making it a #protected or #private property. Then I would have dedicated methods for fetching or inserting data into the actual array inside the data-model class itself. No objects outside of the data-model should actually have direct access to the array or have knowledge of its indexes.
So, in this case your data-model would have something like:
- (NSString *) textForLineAtIndexPath:(NSIndexPath *) anIndexPath{
//... do bounds checking for the index
NSString *returnString=[self.privateArray objectAtIndex:anIndexPath.row];
if (returnString=='sometest'){
return returnString;
}
return #""; //return an empty string so the reciever won't nil out and crash
}
as well as a setTextForLineAtPath: method for setting the line if you need that.
The general instructional materials do not spend enough (usually none) time talking about the data-model but the data-model is actually the core of the program. It is where the actual logic of the application resides and therefore it should be one of the most complex and thoroughly tested class in your project.
A good data-model should be interface agnostic i.e. it should work with a view based interface, a web based interface or even the command line. It should neither know nor care that its data will be displayed in a tableview or any other interface element or type.
When I start a new project, the first thing I do is comment out the '[window makeKeyAndVisible];' in the app delegate. Then I create my data-model class and test it old-school by loading data and logging the outputs. Only when it works exactly how I wish it to do I then proceed to the user interface.
So, think real hard about what you want the app to do on an abstract level. Encode that logic in a custom class. Isolate the data from all direct manipulation from any other object. Verify all inputs to the data before committing.
It sounds like a lot of work and it is. It feels like overkill for a small project and in many cases it is. However, getting the habit early will pay big dividends very quickly as your apps grow in complexity.
Not quite. You want the data source to be an object that implements the UITableViewDataSource protocol; what I would do in this situation is create an object that implements that protocol and parses XML, so that you can alloc-init it, then set the data source to that object and have it update the table view as appropriate. So based off your code (and assuming you're running within the table view's controller):
XMLParserAndDataSource xpads = [[XMLParserAndDataSource alloc] init];
[xpads getXMLData];
self.tableView.dataSource = xpads;
It's probably a good idea to give this class itself a reference to an NSXMLParser object, so you can use that to parse the XML, then provide convenience methods (like getXMLData) as well as the UITableViewDataSource methods for your own use. (If you go this route, you should also make your XMLParserAndDataSource class implement the more useful of the NSXMLParser delegate methods, and use them as appropriate to update your table view.)
I'm a Mac programmer and not an iPhone programmer; but on the mac,
self.tableDataSource = xmlParser.returnedArray is not correct. You are supposed to either bind the table's content to an Array Controller (if iPhone has one?) or set the datasource outlet to your RootViewController.
In your rootview controller, you would implement the methods:
– tableView:cellForRowAtIndexPath:
– tableView:numberOfRowsInSection:
For – tableView:cellForRowAtIndexPath: you would return a UITableViewCell with the data you received from the XML parsing according to the index path like so:
UITableCell *myCell = [UITableCell new];
myCell.textLabel.text = [parsedXMLArray objectAtIndex:[indexPath indexAtPosition:indexPath.length-1]];
return myCell;
(Something people don't know is that you can use the + new class method on all NSObject subclasses which automatically call alloc/init.)
For – tableView:numberOfRowsInSection just return the count of the data array:
return parsedXMLArray.count;
Can't edit my question nor post replies, can only post my response as answer.
#TechZen: I'm somebody who tries to form analogies, helps me understand. What you're saying is something like: My original idea was like going into the file room & dumping all the originals on my desk to work on where as you suggest the object be more like an organised file clerk who will search through the data for me and only return the specific datum that I need while being the only one with direct access to that data.
Have I understood correctly?
#Tim: What if I later need the parser to get data for something which is not a table? That's why I thought to dump it into an array & let the caller decide what to do with the data. Would you suggest a second object that would supply the data in the newly required form? (Am I sort of one the right track here or way off?)

Setting ivar in objective-c from child view in the iPhone

Maybe a FAQ at this website.
I have a TableViewController that holds a form. In that form I have two fields (each in it's own cell): one to select who paid (single selection), and another to select people expense is paid for (multiple selection).
Both fields open a new TableViewController included in an UINavigationController.
Single select field (Paid By) holds an object Membership
Multiple select field (Paid For) holds an object NSMutableArray
Both vars are being sent to the new controller identically the same way:
mySingleSelectController.crSelectedMember = self.crPaidByMember;
myMultipleSelectController.crSelectedMembers = self.crSelectedMembers;
From Paid for controller I use didSelectAtIndexPath method to set a mutable array of Memberships for whom is paid:
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[self.crSelectedMembers removeObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
else {
[self.crSelectedMembers addObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
So far everything goes well. An mutable array (crSelectedMembers) is perfectly set from child view.
But...
I have trouble setting Membership object.
From Paid By controller I use didSelectAtIndexPath to set Membership:
[self setCrSelectedMember:[crGroupMembers objectAtIndex:indexPath.row]];
By NSlogging crSelectedMember I get the right selected member in self, but in parent view, to which ivar is pointed, nothing is changed.
Am I doing something wrong? Cause I CAN call the method of crSelectedMembers, but I can't change the value of crSelectedMember.
If I understand your question, the most likely cause is an improper property declaration.
If you want to pass values from one object to another using each objects properties, then you need to make sure to use assign to ensure the properties in one object are pointing at the same instances as the property in the other object.
So in your topViewController you have a property:
#property (nonatomic,retain) NSString crSelectedMember;
Then in your child view controllers you have:
#property (nonatomic,assign) NSString crSelectedMember;
This forces the value into the exact object in the parent controller.
However, this is a very fragile way to pass data between viewControllers. As your app becomes more complicated, it will be impossible to track all the passed data. (Worse, if you run into memory limitations, the parent view controller may unload and not even exist when you try to pass data to it.)
Instead, you should have a single custom object devoted to holding your data. Each view controller should query that object for the data it needs and should write any changes back to that object. The view controllers never communicate directly. This technique allows you to control the data in one specific location instead of spreading it out all over your code and it scales well. You can add an arbitrary number of view controllers to you app without having to worry about tying them all together.
See this post for details: iPhone: How to Pass Data Between Several Viewcontrollers in a Tabbar App