self.tableview reloadData causing crash in UITableView - iphone

I'm getting this crash when selecting a row: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)',
I moved the data out of the viewWillAppear because we though it was causing a crash. I now have it loading on ViewDidLoad.
However if the [self.tableview reloadData]; is on, I get this crash.
Ideas?
-(void) loadData3;{
MyAppDelegate *AppDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.tableDataSource3 = [AppDelegate.data3 objectForKey:#"Rows"];
NSLog(#"AppDelegate.data3 : %#",AppDelegate.data3 );
NSLog(#"self.tableDataSource3 : %#",self.tableDataSource3 );
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData3];
if(CurrentLevel3 == 0) {
self.navigationItem.title = #"Families I Follow";
}
else
self.navigationItem.title = CurrentTitle3;
}
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated];
[self.tableview reloadData];
}

More than likely, you are changing the Array that loads the UITableView while it is being displayed, so when you click on a Row the row no longer exists in the Array. Therefore, the out of bounds error on the Array.

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
Moving reloadData to viewDidAppear solves this issue.

Since its happening while selecting a row, the error is most likely in your tableView:didSelectRowAtIndexPath: or tableView:willSelectRowAtIndexPath: method(s). Nothing seems intrinsically wrong with the viewWillAppear: code fragment that you've posted.

Related

Irregular behavior using the viewDidAppear and viewDidLoad methods

I am trying to update some of my views when they appear, so I naturally found myself using the viewDidAppear: and viewWillAppear: methods. However, I have experienced two problems with using these methods:
When I only implement one of the methods, the changes that I am looking to make are not completely there, so in order for everything to work, I implemented both methods with the same code.
Even after implementing both methods with the same code, there is a 0.5 to 1 second delay when updating the view's content.
Here is my code for my custom made table view controller:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
For some reason, I must call the reloadData method twice to completely update my table view.
Here is my code for my custom made normal view controller:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
navItem.title = #"Name1";
nameLabel.text = #"Name1";
nameField.hidden = YES;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
navItem.title = #"Name1";
nameLabel.text = #"Name1";
nameField.hidden = YES;
}
Thank you!
You should only use the viewWillAppear method.

The keyboard make the UIView slowly when it comes up?

i have an action that allows me to present a ModalViewController and show the UITextField as a first responder, the problem is when this ModalViewController will come up it takes a little time, the cause is the keyboard, and when i grab the code to the viewDidAppear the keyboard take a little time to show up, so how can i do to make the UIViewController comes up quickly?
- (IBAction)goToModalViewController
{
ModalSearchViewController *msvc = [[ModalSearchViewController alloc] init];
self.msvc.context = context;
self.msvc.delegate = self;
[self.msvc setModalTransitionStyle:UIModalTransitionStyleCrossDissolve ];
[self presentModalViewController:msvc animated:YES];
}
The viewWillAppear of the ModalViewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[findTextField becomeFirstResponder];
}
Try like this in the viewWillAppear.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//[findTextField becomeFirstResponder];
[findTextField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.3];
}

Reload a UIView

I have a view, when it starts, the array of objects is read from memory and the Table View is completed with the objects. When I go to another view and write another objects to file and get back to the first view, the objects are loaded into the array from file as it should but the doesn't reload somehow... [myTableView reloadData] doesn't work, neither does setNeedsDisplay.
-(void)viewWillAppear:(BOOL)animated
{
contactsToLayNow=[NSKeyedUnarchiver unarchiveObjectWithFile:fPath()];
NSLog(#"NOW IN VIEW WILL APPEAR");
for(Contact *cn in contactsToLayNow)
{
NSLog(#"%#", cn.fName);
}
//[self.view setNeedsDisplay];
[quickDialTableView reloadData]; //MOREOVER EXCEPTION HERE IS THROWN
[super viewWillAppear:YES];
}
you will need to retain contactsToLayNow - I guess it's being autoreleased sometime during your tableViews's drawing :)
contactsToLayNow = [[NSKeyedUnarchiver unarchiveObjectWithFile:fPath()] retain];
PS It's not required but you should put your call to super at the top of this method ;)
Move your [super viewWillAppear:animated]; to first line of viewWillAppear: method.

Tableview refreshing to parent view after selecting child using reload data

I have a UITableView that uses JSON to to get new data from the AppDelegate. It saves the data and then is pulled into this tableview class from the AppDelegate.data3, After I add a record to the mysql database I launch the Delegate method that refreshes the data.
However,[self.tableview reLoadData]; breaks the drill down ability of the table, If I select the row, it pushes the child view for a split second and the refreshes the screen with the Parent Rows. If I take out the [self.tableview reLoadData]; The parent pushes to the child but I don't get a refreshed screen with the new data.
Any Ideas?
-(void) loadData3;{
//Initialize table data source
MyAppDelegate *AppDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.tableDataSource3 = [AppDelegate.data3 objectForKey:#"Rows"];
}
- (void)viewDidLoad {
[super viewDidLoad];
if(CurrentLevel3 == 0) {
self.navigationItem.title = #"Parent Table";
}
else
self.navigationItem.title = CurrentTitle3;
}
}
- (void)viewDidAppear:(BOOL)animated {
[self loadData3];
[self.tableview reloadData];
[super viewDidAppear:animated];
}
There are several issues. It's not clear what you are trying to do.
You set self.tableDataSource3 to tempArray, and then set it to [AppDelegate.data3 ....];
Why?
NSArray *tempArray = [[NSArray alloc] init];
self.tableDataSource3 = tempArray;
[tempArray release];
MyAppDelegate *AppDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.tableDataSource3 = [AppDelegate.data3 objectForKey:#"Rows"];
On Startup [self loadData3] gets called twice. Once in viewDidLoad and viewDidAppear. Unnecessary. Should only be in viewWillAppear.
You're either not saving data that you're adding, or not retrieving it properly. Might have to step through your code to see if you're getting the data you should be getting.

Why does viewDidLoad wait before updating the UI?

I'm just trying to get my head around the Objective-C event model on iPhone, and by the looks of things I have fundamentally misunderstood something here.
For the purpose of experimentation, in a view controller's -viewDidLoad method, I am setting a UILabel's text, then sleeping for two seconds, and then changing the label's text again.
My expectations are as follows: the label will first read, "First Text", then two seconds later it will be updated to read, "Second Text." Of course, this isn't quite how it happens. Instead, the view isn't visible at all for two seconds, and finally when it becomes visible its label reads, "Second Text."
Could somebody please explain to me what is going on? I'm interested to find out how you guys would achieve what I'm going for here.
Cheers.
UPDATE 1: Here's the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
label.text = #"First Label";
sleep(2);
label.text = #"Second Label";
}
UPDATE 2: I made a silly mistake here, so please ignore this update.
UPDATE 3: I have now added the following to my viewDidAppear method:
- (void)viewDidAppear: (BOOL)animated {
[super viewDidAppear: animated];
label.text = #"First Label";
sleep(2);
label.text = #"Second Label";
}
Unfortunately I'm having exactly the same problem.
UPDATE 4: Following gerry3 and Felix's suggestions, I have now implemented a performSelector, and boom! Works a treat!! I'm going to have to give it to gerry3 though as he certainly put the most amount of effort into helping me out. Thanks for all your contributions!
I guess the reason is that viewDidLoad runs on the mainThread as do all UIKit interactions. The UI can only be updated on the mainThread hence if you block the viewDidLoad with sleep(2) you are putting the mainThread to sleep and halt all userinterface updates on that thread.
Use NSTimer if you want to update the UI after a certain amount of time, rather than using sleep(2). Or use performSelector:withDelay: on self to perform a method later without blocking the mainThread.
Same holds true for viewDidAppear and viewWillAppear. Both run on the mainThread.
Put your code that modifies the view in viewDidAppear:.
The view is not yet visible when viewDidLoad and viewWillAppear: are called.
UPDATE
Just to be clear, I agree with the others that the correct way to do this is with a delayed method call or timer.
UPDATE 2
Here is the code that I am suggesting:
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"View will appear!");
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"View did appear!");
label.text = #"First Label";
sleep(2);
label.text = #"Second Label";
}
And the "correct" way:
- (void)viewDidLoad {
[super viewDidLoad];
label.text = #"First Label";
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"View will appear!");
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"View did appear!");
[self performSelector:#selector(changeLabelText) withObject:nil afterDelay:2.0f];
}
- (void)changeLabelText {
label.text = #"Second Label";
}
I do not think you really want to be calling sleep in that method. This is something you should try and use a Timer for to avoid blocking the UI and the whole application. A Timer will let you call some code either just one or repeatedly. See the guide for more info
The signature of the viewDidAppear and viewWillAppear are wrong in your sample..they should be
- (void)viewWillAppear: (BOOL)animated {
NSLog(#"View will appear!");
}
-(void)viewDidAppear : (BOOL)animated {
NSLog(#"View did appear!");
}
The frameworks will not call implementations with the wrong signature as the message dispatch does not find them.