Odd problem loading data into a text view field - iphone

BRIEF: Hi everyone, painfully working through my first app and couldn't find a solution online for this "loading" issue.
ATTEMPTING TO DO: (a)From a table view (b)click on a cell (c)push into a detail view where a text view field is populated from a property list file.
PROBLEM: Everything works (Nav bar title updates, backbutton title changes correctly) but the text view field comes up blank (default state from IB)... at first. If I click the back button, then back into the detail view, the text view then loads correctly and stays that way. Totally baffled.
CODE:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// check for view controller
if (self.savedScriptDetailVC ==nil) {
SavedScriptDetailVC *savedScriptDetail =[[SavedScriptDetailVC alloc]initWithNibName:#"SavedScriptDetailView" bundle:nil];
self.savedScriptDetailVC = savedScriptDetail;
[savedScriptDetail release];
}
// find row
NSInteger row = [indexPath row];
//get filepaths and set up arrays for pulling project names and text data
NSString *textPath = [self savedScriptsPath]; //using outside function to get path
NSArray *array = [self savedProjectNames]; //using outside function to pull project names
NSArray *textArray =[[NSArray alloc] initWithContentsOfFile:textPath];
textArray = [textArray valueForKey:#"ScriptText"];
//populate text for textview in detail view. Works, but have to drill down, back out before effect takes, why?-->
savedScriptDetailVC.fScriptText.text = [NSString stringWithFormat:#"%#", [textArray objectAtIndex:row]];
savedScriptDetailVC.title =[NSString stringWithFormat:#"%#", [array objectAtIndex:row]]; //change nav title
//change back button text
UIBarButtonItem *backButton =[[UIBarButtonItem alloc]initWithTitle:#"Scripts" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem =backButton;
[backButton release];
//using delegate to push views
ProjectAppDelegate *delegate =[[UIApplication sharedApplication]delegate];
[delegate.savedScriptsNavC pushViewController:savedScriptDetailVC animated:YES];
}

The actual view (and all its subviews) for a view controller is not loaded until it is needed, i.e. the view property is accessed. So at the point that you first try to set the value of the text field, the text field doesn't exist yet because none of the views in the view controller have been created yet. If you were to check, you would find that savedScriptDetailVC.fScriptText is nil.
A simple fix is to access [savedScriptDetailVC view] before trying to manipulate those subviews.

I agree with Anomie's explanation: the first time you try to set the text of the text field, the text field is nil so nothing happens. I recommend a different solution, however. Give SavedScriptDetailVC one or more properties where you can store whatever information it needs to do its job, and set those properties before you push the controller onto the navigation stack. Let SavedScriptDetailVC be responsible for properly configuring the views that it manages, probably in its -viewWillAppear method.
In general, the only object that should manipulate a view controller's views is that view controller. If you adopt that philosophy you'll completely avoid the kind of problem you're having now.

Related

UITableView and background image shift down after dismissing modalview

I have a view with a tab bar and a table view in it. At a certain point I call a modal view, and when I dismiss it, the original view seems to stretch or shift down, as the background image is lower and the table view is longer to the point that the last cell goes outside of the frame.
I call the modal view from tableView:didSelectRowAtIndexPath:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *row = [[[[self.productDetails valueForKey:#"sections"] objectAtIndex:indexPath.section] valueForKey:#"rows"] objectAtIndex:indexPath.row];
NSMutableDictionary *post = [self.productDetails valueForKey:#"post"];
if ([[row valueForKey:#"type"] isEqualToString:#"pick"])
{
self.xPicker = nil;
self.xPicker.options = nil;
self.pickerOptions = nil;
self.xPicker = [[[TablePicker alloc] initWithNibName:#"TablePicker" bundle:[NSBundle mainBundle]] autorelease];
NSMutableDictionary *newPicker = [[[NSMutableDictionary alloc] init] autorelease];
[newPicker setValue:[NSString stringWithFormat:#"%d", indexPath.section] forKey:#"section"];
[newPicker setValue:[NSString stringWithFormat:#"%d", indexPath.row] forKey:#"row"];
[newPicker setValue:[row valueForKey:#"options"] forKey:#"options"];
[newPicker setValue:[row valueForKey:#"value"] forKey:#"value"];
self.xPicker.options = [NSMutableDictionary dictionaryWithDictionary:newPicker];
self.pickerOptions = [NSDictionary dictionaryWithDictionary:newPicker];
self.xPicker.view.frame = self.view.bounds;
[self presentModalViewController:self.xPicker animated:YES];
}
}
Inside the modal view controller, I do some stuff, then fire a notification to let the parent controller know that it's ok to dismiss it. This part doesn't feel right, but I was getting an error occassionally when I had the modal view call:
[self.parentViewController dismissModalViewControllerAnimated:YES];
Anyways, the code block where I dismiss the modal view is as follows:
- (void) reloadCell
{
[self dismissModalViewControllerAnimated:YES];
if (self.xPicker.choice != nil)
{
NSDictionary *choice = self.xPicker.choice;
NSMutableDictionary *row = [[[[self.productDetails valueForKey:#"sections"] objectAtIndex:[[choice valueForKey:#"section"] intValue]] valueForKey:#"rows"] objectAtIndex:[[choice valueForKey:#"row"] intValue]];
[row setObject:[choice valueForKey:#"value"] forKey:#"value"];
[[self.productDetails valueForKey:#"post"] setObject:[choice valueForKey:#"value"] forKey:[row valueForKey:#"key"]];
Request *xReq = [[[Request alloc] init] autorelease];
[NSThread detachNewThreadSelector:#selector(updateOrderFromProductDetails:) toTarget:xReq withObject:[self.productDetails valueForKey:#"post"]];
self.xPicker = nil;
}
}
I don't know if it's related, but I found it interesting that when I present this modal controller while the device is in landscape mode, the view goes wonky.
Does anyone know how to fix this?
Edit: After some searching, it appears that both problems are related and have to do with my current view controller being a subview of another view controller, but not through a navigation controller.
As I understand it, my decision to not use a nav controller is confusing my view stack somehow. I had a feeling that would come back to bite me in the butt.
Unfortunately, I can't seem to find a solution to my problem anywhere.
If you have a nib associated with the views - go into the nib for each view and set the following attributes on the main view in each nib:
status bar: unspecified
top bar: unspecified
bottom bar: unspecified
Then in the size:
x:0,y:0,W:320,H480
Back in the code after you've allocated each view also set the 'wantsFullScreenLayout' property to TRUE on each view.
Edit: explanation (? maybe ? :-))
If you have a status bar specified in the nib then the uikit automatically adjusts your views to cater for the status bar (and you'll see that your view yorigin is 0 and height is 460 in the nib) but if you look at the offset/height in the frame in your viewDidAppear method its been set to 20/460 to cater for the status bar.
For some reason presenting modal view controllers seems to mess with this and adjust for the status bar again, shifting your view down another 20. Setting status bar to unspecified and setting wantsFullScreen layout stops uikit messing with your frame and gives you control (hence setting height to 480 in the nib sizing).
You will also need to move all of your view elements down by 20 to cater for the status bar height in the 480 height view.
Ok, I have one solution to this problem.
Instead of having my current view controller call presentModalViewController, I call it from the appDelegate tabBarController like so:
[[(myAppDelegate *)[[UIApplication sharedApplication] delegate] tabBarController] presentModalViewController:self.myModalViewController animated:YES];
This still feels a bit hacky, but it solves both problems of
1) resizing when the modal view is dismissed
2) the modal view being unable to pop up in landscape mode
I hope this can help someone else out there in this cruel Apple world.
When your main view comes back, try adding:
[myTableView setFrame:CGRectMake(0,0,320,411)];.

UIPopoverController with UITableView

I have a UIPopoverController that has a UITableView that is populated. I am trying to pass the information from the popovercontroller to the superview. The tableview that is placed in the popovercontroller is receiving the information with the didSelectRow method but the information is not transferring to the textView placed in the superView.
Below is the code I use to try and place the selected user in the textview and underneath that is the Superview code where I try to take the string and place it into the actual field when the index is clicked. I know my issue is I am not telling my superView that the row was touched and to send that information into the field but I have searched and con not find a good explanation on how to attempt this.
If anyone has any suggestions that would be great!
thanks
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath {
if (indexPath){
NSString *selectedUser = [(Tweet*)[Friend objectAtIndex:indexPath.row]
followingScreenName];
TwitterFollowersTimline *textBox = [[TwitterFollowersTimline alloc]
initWithNibName:#"TwitterFollowersTimeline" bundle:[NSBundle mainBundle]];
textBox.selectedFriend = selectedUser;
NSLog(#"%#", selectedUser);
[textBox release];
textBox = nil;
}
}
In my SuperView
selectedFriend = [[NSString alloc] init];
creatTweetText.text = [NSString stringWithFormat:#"#%#", selectedFriend];
In order to pass information from the View Controller of the popover you're going to want to set up a delegate. Here's a link to Apple's documentation and also a good guide example.
https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
Essentially when you create the View Controller that houses the methods for your table view, you'll want to give it a delegate. Then once a cell is selected in your table view, you'll be able to send a call to your delegate with any information you need.

taking string from a text field and passing it to the previous viewController

im my app that im tring to build, i want to have a table view, where you select a row e.g email address. the view pushes to a simple page with a uitextField, when you hit the save button it pops the view controller back to the initial page, where the user can select the next field.
the issue that i am having is passing the information entered in the textfile back to the first view controller. this should be really simple, but anything i try just does not work
what is the best way to go around this.
thanks
You are probably thinking about the problem backwards. In an MVC system like Cocoa, the job of View Controllers is to manage views, not data. Create a model object to hold the data you're updating. When you create a view controller, pass the model object to it. It may update the model with changes the user makes. It should not worry about who called it, or who it returns to. It should just update the model object, and other interested parties should read the model object. As an example:
SettingsViewController would have a model object called Settings
When you dive into a detail view controller like EmailViewController, you pass the settings to it like emailViewController.settings = self.settings before presenting it.
When the user makes changes, just update the object like self.settings.emailAddress = ...
This separates your view logic from your model logic, which is a key features of Cocoa patterns. If you fight this pattern, you're going to often find yourself thinking "it sure is hard to get there from here."
You can either use a delegate method or, even simpler, just define an instance variable NSString *textEntry in the first view controller that can be set (property/synthesize) and then access that view controller from the stack.
For example, in the pushed view, do something like:
FirstViewController *firstViewController = [[[self navigationController] viewControllers] objectAtIndex:0];
[firstViewController setTextEntry:[textfield text]];
The easiest way I found to do this is using NSNotificationCenter.
In the ViewController with the TableView:
- (void)updateRowValue:(NSNotification *)notification{
NSDictionary *valuesDictionary = [[NSDictionary alloc] initWithDictionary: [notification userInfo] copyItems:NO];
NSString *newString = [valuesDictionary objectForKey:#"StringVal"]
}
This is the method called when row is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TextFieldViewController *tfvc = [[TextFieldViewController alloc] init];
[tfvc setPostNotificationString:#"updateRowValue"];
[self.navigationController pushViewController:tfvc animated:YES];
}
Now in the viewController with the textField, when you press the button to return to the previous viewController call this:
- (IBAction)saveButtonPressed{
NSArray *valuesArray = [[NSArray alloc] initWithObjects:textField.text,nil];
NSArray *keyArray = [[NSArray alloc] initWithObjects:#"StringVal",nil];
NSDictionary *dictionary = [[[NSDictionary alloc] initWithObjects:valuesArray forKeys:keyArray] autorelease];
[[NSNotificationCenter defaultCenter] postNotificationName:[self postNotificationString] object:self userInfo:dictionary];
[[self navigationController] popViewControllerAnimated:YES];
}

Need help with table view detail view. I can't seem to write values to the UILabel's text property?

I have a TableView setup as my "root view controller" and a detail view controller called "DetailController" to allow me to display the detail view for what the user selects in the main table view. The navigation is working correctly - when I select a row in my table the screen slides to the left and I'm presented with my detail view, but I can't update the detail view's UILabel text properties. It's like it is just ignoring my UILable set property methods (see code below) as it isn't giving me any errors or warnings.
I've tested that I do have the values I need when I hit the "tableView:didSelectRowAtIndexPath:" method, but for some reason I can't seem to update the detail view's UILabels' text properties. Using NSLog's I can see that I am getting the values and passing them correctly to the UILabels. However the detail view isn't showing the passed values in its UILabels.
The strange thing is that I CAN set the detail view's title property correctly, just not the UILabel properties, which is very confusing!
Here's my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (self.detailView == nil) {
DetailController *detail = [[DetailController alloc] initWithNibName:#"DetailController" bundle:nil];
self.detailView = detail;
[detail release];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSDictionary *dict = [[NSDictionary alloc] initWithDictionary:[theList getItem:cell.textLabel.text]];
[self.detailView.theID setText:#"LOOK AT ME NOW!"];
self.detailView.thePrice.text = [[dict objectForKey:#"PRICE"] stringValue];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:self.detailView animated:YES];
NSString *newTitle = [[NSString alloc] initWithString: #"Viewing Attributes for: "];
newTitle = [newTitle stringByAppendingString:cell.textLabel.text];
self.detailView.title = newTitle;
[dict release];
[newTitle release];
}
Thanks for any help on this! I love this community - you guys are awesome!
I Found An Answer! I think...
After much trial and error I was able to figure out a solution, but the solution doesn't entirely make sense to me and still leaves me with questions.
Siegfried suggested that I move my "pushViewController" message to the end of the method so that the last six lines of my code were changed to:
// Pass the selected object to the new view controller.
NSString *newTitle = [[NSString alloc] initWithString: #"Viewing Attributes for: "];
newTitle = [newTitle stringByAppendingString:cell.textLabel.text];
self.detailView.title = newTitle;
[dict release];
[newTitle release];
[self.navigationController pushViewController:self.detailView animated:YES];
}
When I moved it to the last line (as shown above) my program would crash with an EXC_BAD_ACCESS error. I still don't understand why moving that line of code to the end of my method caused the program to crash?
However, this got me thinking - I was able to successfully change the title of the new detail view, but not the view's UILabel properties. So I moved my pushViewController method back to where it was and then moved my methods for setting the new view's UILabels underneath the pushViewController method and BOOM! Everything worked! The new detail view was being pushed when the user clicked on the row in my table and its properties (title and UILabels) were all being set correctly.
Why does this work?
I remember reading about how the iPhone handles views, something called "lazy loading" or "lazy instantiation"? I think this means that I can't change the properties of my detail view UNTIL I've "pushed" it, which is when the object is actually created in memory and its properties become available?
If this is correct, that would kind of explain the error I was getting when I moved the pushViewController method to the end of my code - I was trying to change the title property on a view that wasn't instantiated. However, that doesn't completely make sense because I was trying to change the UILabel properties of the view in my original code, which was before the view was actually pushed and the program wasn't crashing?
So my code that is currently working looks like the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (self.detailView == nil) {
DetailController *detail = [[DetailController alloc] initWithNibName:#"DetailController" bundle:nil];
self.detailView = detail;
[detail release];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSDictionary *dict = [[NSDictionary alloc] initWithDictionary:[theList getItem:cell.textLabel.text]];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:self.detailView animated:YES];
// Moved the "set property" methods to happen after the detail view is pushed
[self.detailView.theID setText:#"LOOK AT ME NOW!"];
self.detailView.thePrice.text = [[dict objectForKey:#"PRICE"] stringValue];
NSString *newTitle = [[NSString alloc] initWithString: #"Viewing Attributes for: "];
newTitle = [newTitle stringByAppendingString:cell.textLabel.text];
self.detailView.title = newTitle;
[dict release];
[newTitle release];
}
I like that the code is working, but I would really like to understand what was and is actually happening. Can anyone offer additional insight here?
Thank you!
Move
[self.navigationController pushViewController:self.detailView animated:YES];
to last line.
You may try doing:
NSString *strText = [NSString stringWithFormat:#"%#",[[dict objectForKey:#"PRICE"] stringValue]];
self.detailView.thePrice.text = [NSString stringWithFormat:#"%#",strText];
Check wheather strText is containing the expected value and is not nil.

UINavigationController, UITableView and not showing the next view

I am having a problem with a table and showing another view when the user touches a table cell. I am using a UITabBarController for the main view to show different views. I then use a UINavigationController when the user selects a UITableView view to display the next view from the table cell selection.
My problem is this: when they select the table cell, the cell is highlighted and the next view does not appear. I am using IB. All of the examples I have found are doing this the same way I am, except the examples work!
I have the controllers loaded in a NSMutableArray with a Dictionary. I also tried this code by directly creating a view controller rather than using the array item. Same results....
I checked the target controller (Calc1ViewController) to make sure there was nothing wrong with the controller. When showing it directly, the controller (Calc1ViewController) displays correctly.
Here is some code.....
The initialization of the view controller in the dictionary:
Calc1ViewController *calc1ViewController = [[Calc1ViewController alloc] init];
[menuList addObject:[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(#"SSC - page 1",#""), #"title",
calc1ViewController, #"viewController",
nil]];
[calc1ViewController release];
I also tried this without using the dictionary -- creating a view controller in place of the [[menuList objectAtIndex:...]; line -- by creating the view controller like this:
Calc1ViewController *targetViewController = [[Calc1ViewController alloc] init];
// the table's selection has changed, switch to that item's UIViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *targetViewController = [[menuList objectAtIndex: indexPath.row] objectForKey:#"viewController"];
[[self navigationController] pushViewController:targetViewController animated:YES];
targetViewController = nil;
}
The navigation controller is defined in the AppDelegate and connected to the RootViewController through IB.
When I select a table row, it shows in the debugger that the pushViewController code is executed, but the next view does not show. Here is an example:
alt text http://thecoolestcompany.com/ssc-table-view.jpg
Any ideas?
Finally figured it out......
I had the UINavigationController and the UITabBarController on the same level. After moving the Navigation Controller as a child to the tab bar controller, everything worked. You may add as many navigation controllers to a tab bar as you would like. In IB is is a little confusing. You need to drag the NavigationController into the TabBar to as it as a new Tab Bar item.
Theres not much to go by with t he code you have provided. Only thing i can think of without looking at more code is that perhaps you have not initialized your view controller (the one in your dictionary) correctly, or at all, or the dictionary you are accesing there is not the correct one...
What is the value of [self navigationController] when pushViewController is called. Is it nil?
What is the value of targetViewController when it is passed to pushViewController. Is it nil?