So I have a UITableView which should loop through a single NSMutableArray and use each of them as row labels. Currently the only way I can get this to run is with 0 or 1 rows, 2 or higher throws out an error saying the array index is off. I tried NSLog to output my array and can confirm it's reading all the Strings.
// table methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell...
NSString *cellValue = [harvestRecipeList objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
The array code is stored in the exact same file (MasterViewController.m) which I added below.
- (void)viewDidLoad
{
[super viewDidLoad];
harvestRecipeList = [[NSMutableArray alloc] init];
[harvestRecipeList addObject:#"Ice Cream"];
[harvestRecipeList addObject:#"Walnut Cake"];
[harvestRecipeList addObject:#"Cookies"];
[harvestRecipeList addObject:#"Salad"];
[harvestRecipeList addObject:#"Grilled Fish"];
//Set the title
self.navigationItem.title = #"BTN Recipes";
}
I would love any help on this it's been bugging me. I was using [harvestRecipeList count] but this throws the same array index error. And as I mentioned I can get the app to run perfectly fine with 0 or 1 rows - thanks in advance for any help!
EDIT: here is the error I'm getting in the output window after building:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
EDIT2: included below my property setup for harvestRecipeList
//MasterViewController.h
#interface MasterViewController : UITableViewController {
NSMutableArray *harvestRecipeList;
}
#property (nonatomic, retain) NSMutableArray *harvestRecipeList;
// and also my MasterViewController.m
#synthesize harvestRecipeList;
EDIT3
here's my source code zipped for this project. It's called treehouse, just a testing name for now but you can dl from my cloudapp here.
Updated Solution:
So I have checked your code and found the problem. Do the following:
Go into your storyboard and select the Master Table View (click where it says Static Content)
Click on the Attributes Inspector (looks like a downward arrow sort of) and change the content from Static Cells to Dynamic Prototypes
Click on the prototype cell and type Cell into Identifier field (this is what you are using as a cell ID
Also change the Accessory from None to Disclosure Indicator
In your tableView:numberOfRowsInSection return self.harvestRecipeList.count
In tableView:cellForRowAtIndexPath: you can remove the following two lines (as they are provided by the Storyboard):
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
Recreate your Push segue from your Master Cell to your Detail View Controller
It should all now work fine - and I've tested that it works. The basic problem was you had specified Static Cells rather than Dynamic Prototypes and the rest of the instructions are just mopping up. The NSRangeException was caused by only having a single cell so that was all that was displayed.
Hope this helps.
Previous Solution:
So, a few comments but, first, if you've updated your code can you post an update?
Your harvestRecipeList that you add objects to in ViewDidLoad does not appear to be the same harvestRecipeList that you synthesised - it will be local to the method so your instance variable will always be nil. You should always use self.harvestRecipeList - do this everywhere. This could easily explain your NSRangeException. Also see #4 below.
In your tableView:numberOfRowsInSection: you should return self.harvestRecipeList.count
If you are using the iOS5 SDK, you do not need to check if cell == nil as dequeueReusableCellWithIdentifier: is guaranteed to return non-nil cell. You do need to check if you are on the iOS4 SDK.
Change your #synthesize harvestRecipeList; to #synthesize harvestRecipeList = _harvestRecipeList; as this will assist with #1 and checking you are accessing the ivar.
Try #1 & #2 as a minimum and then post an update on the problems you are having. Hope this helps.
I examined the code you put in the ZIP file. I immediately noticed your using the iOS 5 Storyboard feature. I haven't got Xcode 4 nor the iOS 5 SDK, so I could not test that part of your application.
However, I went on and coded your Storyboard part by hand. I have tested your MasterViewController solely and found no errors. I added in the AppDelegate this method to replace the Storyboard automatical features and just show the view controller where you think the error is coming from.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MasterViewController *myVC;
_window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]];
myVC = [[MasterViewController alloc] initWithStyle:UITableViewStylePlain];
[_window setAutoresizesSubviews:YES];
[_window addSubview:myVC.view];
[_window makeKeyAndVisible];
return YES;
}
To prove your MasterViewController.m contains no error, I add this screenshot:
Conclusion: Your error is to be found somewhere else, probably in your Storyboard file. However I have never used that new functionality so I cannot help you with that. I suggest you review your Storyboard and put all attention to that file.
Okay, if your log messages display an array with five objects right before you try to query the second, and you application gives you an NSRangeException the bug is definitely not to be found in the code you show us.
Try to find it by placing various logs before and after any -[NSArray objectAtIndex:] and see which log doesn't come through after the call. There's your error.
Remember you can use
NSLog(#"%s", __PRETTY_FUNCTION__);
to show where you log message is coming from. Their also exists a line and file macro, but normally the function macro should help you enough.
Example:
NSLog(#"%s Before", __PRETTY_FUNCTION__);
[myArray objectAtIndex:anIndex];
NSLog(#"%s After", __PRETTY_FUNCTION__);
If your second log message doesn't come through, then you'll have found your error.
It is always best to use the setter and getter methods for your instance variables. It takes care of a lot of problems. My guess is that is your problem. So anywhere you want to use harvestRecipeList use self.harvestRecipeList
It would be useful to know what your property declaration is for harvestRecipeList
Related
I'm getting an error when a button press loads the class posted below.
The code is supposed to load a slide out menu. This is the line that is causing my issues. I'm completely new to iOS / obj-c. I'm not sure why, but the method this line of code is in, loops through for each entry in the _menuItems array? The NSLog outputs for each item of the array, but then it runs another time and throws this error? Thats what I think is happening at least. If anyone could give me some pointers, I'd be grateful. Aside to all that, my project has two targets - I don't know why, I don't know how, and I don't know how to change it. Could that be the issue?
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
The console printout is this:
013-11-28 12:11:31.902 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.908 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.911 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.917 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.921 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.924 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.929 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.931 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.932 DatabaseTest[57858:a0b] *** Assertion failure in -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:5261
2013-11-28 12:11:31.936 DatabaseTest[57858:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier tag - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
.
#import "SidebarViewController.h"
#import "SWRevealViewController.h"
#interface SidebarViewController ()
#property (nonatomic, strong) NSArray *menuItems;
#end
#implementation SidebarViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
self.tableView.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
self.tableView.separatorColor = [UIColor colorWithWhite:0.15f alpha:0.2f];
_menuItems = #[#"title", #"news", #"comments", #"map", #"calendar", #"wishlist", #"bookmark", #"tag"];
}
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[_menuItems objectAtIndex:indexPath.row] capitalizedString];
if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.menuItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
NSLog(#"The code runs through here!");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
#end
You must use
static NSString *CellIdentifier = #"messageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Do not use if your cell is not registered a class or nib with Cell ID;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
Apple Documentation:
Important
You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
Edited:
This is wrong:
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
Unless you have registered a cell for each row this isn't going to work.
You need to use a cell identifier that has been registered either in code or from the storyboard / xib.
also - the way you are doing this now takes no advantage of cell reuse if each cell loads a cell with a unique identifier.
I am not sure if you still after the answer for this question, but if you are here is the way you could solve your problem.
Your problem arises from the fact that the cell hasn't got an identifier or if it does, the identifier doesn't match the code in the NSArray *menuItems. To solve the problem:
you should go to the Document Outline (The small arrow at the bottom left of your storyboard)
then you should click on the 'Table View Cell - tag. (It should highlight the cell 'Tag'
Go to the Attributes Inspector and find 'Identifier'
Finally, change or ad the Identifier name, in your case 'tag'.
Et voila!, that should do the trick
Beware of spelling as Objective C is very tight on spelling, I mean you have to make sure the same way you spell the identifier, you must use the same spelling in your code.
Hope that help,
See picture: (I wanted to post one for you, but it seems like I cannot do so, Ooops!)
I'm developing an application in iPad 6.0 using Storyboards.
Let me first explain my goal. I'm trying to achieve a Master-Detail (SplitViewController-like) View Controller using 2 UITableViewControllers.
The first UITableView("Master"), let's call this HeaderTableView, as the name implies, lists down the Headers for the...
...Second UITableView("Detail"), let's call this the EncodingTableView, which contains a programmatically changing CustomTableViewCell (subviews contained within each cell may be a UITextField, UIButton or UISwitch).
See EncodingTableView.m
- (void)updateEncodingFields:(NSArray *)uiViewList
{
// Add logic for determining the kind of UIView to display in self.tableView
// Finally, notify that a change in data has been made (not working)
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *encodingFieldsTableId = #"encodingFieldsTableId";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:encodingFieldsTableId];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:encodingFieldsTableId];
}
// Change text in textView property of CustomTableViewCell
cell.encodingFieldTitle.text = uiViewList.title;
// added methods for determining what are to be added to [cell.contentView addSubView:]
// data used here is from the array in updateEncodingFields:
}
My HeaderTableView.m, contains the didSelectRowAtIndexPath to update the EncodingTableView
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (![selectedIndexPath isEqual:indexPath]) {
selectedIndexPath = indexPath;
[self updateDataFieldTableViewForIndexPath:indexPath];
}
}
- (void)updateDataFieldTableViewForIndexPath:(NSIndexPath *)indexPath {
[self.encodingTableView updateEncodingFields:self.uiViewList];
}
Question
- Data is all ok but why doesn't EncodingTableView "redraw"ing the fields? My
suspicion is that reusing cells has something to do with this but I just can't figure out why.
Screenshots on the result:
Initial Selection in HeaderTableView
Second Selection in HeaderTableView
What I've tried :
I kept seeing suggestions such as [UITableView setNeedsDisplay],
[UITableView reloadData] and [UITableView setNeedsLayout] but none of
them worked.
Removing the reuse of tableViewCells works fine but this causes parts of my
CustomTableView.encodingFieldTitle to disappear. Not to mention that this might cause performance issues if I were to drop reusing cells.
Restrictions:
I know that a good idea is to use a SplitViewController but this is just a subpart of my app (hence not the RootViewController).
Finally, thanks for reading such a long post. ;)
It looks like you are most likely adding subviews inside tableView:cellForRowAtIndexPath:.
The issue is that if you use cell reuse then are not always starting from a blank slate inside tableView:cellForRowAtIndexPath: instead you can possibly be given a cell back that has already been configured once. This is what you are seeing, a cell that has previously had labels added to it is handed back to you and then you add some more labels over the top.
There are a few way to deal with this:
(My preferred option) Create a subview of UITableViewCell with these extra sub views available as properties.
Ensure the cell setup is only done once
A great place to do this is when you actually create a cell when one does not already exist e.g. inside the if (cell) check
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:encodingFieldsTableId];
// add subview's here and give them some way to be referenced later
// one way of doing it is with the tag property (YUK)
UILabel *subView = [[UILabel alloc] initWithframe:someFrame];
subView.tag = 1;
[cell.contentView addSubview:subView];
}
UILabel *label = (id)[cell.contentView viewWithTag:1];
label.text = #"some value";
One problem i can see in your code is that the cell identifiers used are different in tableView cellForRowAtIndxPath function.
While dequeueing you are using this identifier - > "encodingFieldsTableId"
&
while creating a cell you are using this identifier - > "dataFieldUiGroupTableId".
Ideally these two identifiers should be same !!!
Try adding,
cell.encodingFieldTitle.text = nil;
Before if(cell == nil)
So that whenever your cellForRowAtIndexPath method is called, the string already present in the cell you are going to reuse will get deleted and the new text in uiViewList.title will be displayed.
So I've been given an assignment in my Mobile apps class: make a color game app for the iphone.(The description of how to game works is at the top of the pasted viewcontroller.h file below.)
I'm very new to Objective-C and cocoa, but have managed to troubleshoot and fix a lot of things in this app. The problem I have right now is that I don't know how to properly initialize and send UITableViewCells to the view. I'm confused because all of the tutorials I've found online use datasource methods to change different attributes of the UITableView and the cells as well. I'm not sure how these methods will interact with the controls I've already placed. I'm confused because I added them by the storyboard file, not by defining tableview attributes with datasource code.
My immediate issue is that my program won't display the proper text to the cells textlabel and detailtextlabel.
I've looked everywhere online for UITableView and UITableViewCell tutorials, but they are all from years ago and I'm not sure if the advent of the storyboard has changed the way I would treat these controls.
All of the code I've written is either in the viewcontroller.m or viewcontroller.h files.
The method within ViewController.m file, that should call the cell and display text and detail text:
-(IBAction)enterClicked
{
//On enter- send instance colors to the colorTable row[i], perform comparisons and append the resulting symbols to the instanceResults String. Send instanceResults string to the resultTable row[i]. When game counter reaches 6, gameOver. If on comparisons check, the instanceColors are the same as the gameColors, then the player wins.
[self checkForLoss];
if(!self.gameOver)
{
resultOfGuess = [self comparePlayerInputToGameColors:guessColors];
[listOfGuesses addObject:guessColors];
[listOfOutcomes addObject:resultOfGuess];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_numberOfTurnsPlayed inSection:0];
UITableViewCell *thisCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
thisCell.textLabel.text = [self.listOfGuesses lastObject];
thisCell.detailTextLabel.text = [self.listOfOutcomes lastObject];
[guessColors setString:#""];
if([self checkForWin:resultOfGuess])
[UpdateLabel setText:#"You have won!"];
else
[UpdateLabel setText:#""];
self.colorCounter = 0;
self.isStepOne = YES;
_numberOfTurnsPlayed++;
}
else
{
if([self checkForLoss])
[UpdateLabel setText:#"You have lost!"];
}
}
The UITableView DataSource Methods I've called at the bottom of the viewcontroller.m file:
#pragma mark - UITableViewDataSource protocol
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if(section == 0)
return #"Guesses: Results:";
return 0;
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 6;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
return cell;
}
So my questions are: Can I change a control's properties with datasource methods, if I created the controls through the storyboard? How do I properly display the text in a uitableview's cells?
Edit/update: Thank you, I've used your advice jrturton, but now I've found something peculiar that may be the source of my problems. in my viewController.h file I've changed my header from
ViewController: UIViewController to ViewController: UITableViewController
Thinking that the datasource methods I call within the viewcontroller files have to be able to call the same methods and properties of the class that I call in the header-- Also, I see this done in other UITableView tutorial files.
The problem is that when I change the header to read-- ViewController: UITableViewController -- and I try to compile, I get this error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UITableViewController loadView] loaded the "2-view-3" nib but didn't get a UITableView.'
It compiles fine if I use just :UIViewController in the header file though.
Any ideas?
Further update: I''ve noticed within my storyboard that the only available ViewController object is a UIViewController object, while in the other tutorial files I've seen, this ViewController object is a UITableViewController object. I imagine this is my problem, but I can't seem to switch my UIViewController object to a UITableViewController. All I can do is create a new one, which isn't what I want, I imagine.
Your action method should update the data model (which I think it does, since it changes your listOfGuesses array). You then need to let your table view know that you have added or updated rows so that it can re-load them for you - check the UITableView documentation for reloading data or specific rows.
Creating a cell outside of the datasource methods isn't going to let that cell appear in your table.
At the moment I'm guessing you have 6 empty cells in your table view? You need to populate the text and detail labels in your cellForRowAtIndexPath method. The difference now there are storyboards is that you don't need to do the if (cell == nil) bit, as long as you have set the re-use identifier in your storyboard prototype cell then it will do all that for you. So your cellForRowAtIndexPath method can be reduced to:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// This will dequeue or create a new cell based on the prototype in your storyboard
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
// Put your actual configuration here based on your model array
cell.textLabel.text = #"Hello";
return cell;
}
Further hints (this is homework so I'm not giving full samples)
'indexPath.row` in the above method will give you the index from your model array that the cell refers to
You have defined the table as having 6 rows, but you are adding items to your model arrays as you go - so when the table asks for row 5, and your model only has 3 entries, you need to deal with this. Consider changing the number of rows in the table dynamically and using table view methods to indicate that new rows have been added. Again, see the UITableView documentation for this.
Typically the text is set in each cell by accessing the setText property:
[[cell textLabel] setText:#"static string"];
or
[[cell textLabel] setText:someNSString];
or with .dot notation
cell.textLabel.text = someNSString;
return cell;
BTW this is done in the method:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:
I'm having a hard time debugging an issue when presenting a modal view controller. I'm seeing a pause of between 0.5 seconds and 1 second between viewWillAppear being called and viewDidAppear being called on the presented (table view) controller. I tried replacing this with a bare bones table view controller to see if the issue was in the controller calling presentModalController, and it appeared quickly as expected.
I've peppered both controllers with NSLog statements in an attempt to diagnose the issue, but can't narrow it down further than a delay between viewWillAppear and viewDidAppear.
Short of rewriting the controller line by line, what's the best way for me to find out where the issue is? Are there any usual suspects here I should be aware of?
Edit : update with problematic code
The table view is displaying 2 cells, each containing a text field.
I have UITextField properties for each of the 2 text fields
#property (nonatomic, retain) IBOutlet UITextField *itemTextField;
and assign text fields to these properties as follows :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
if (indexPath.row == 0) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
cell.textLabel.text = #"Item";
textField.placeholder = #"Enter item name";
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyNext;
self.itemTextField = textField;
[cell addSubview:textField];
[textField release];
}
}
return cell;
}
I've left out the second row, but the code is the same.
If I comment out
self.itemTextField = textField;
the view loads as expected, but uncommented causes the slight delay I've been seeing. Should I be initialising this somewhere else rather than in cellForRowAtIndexPath? I'm a bit stumped.
Use Time Profiler in Instruments to see which is the offending code. Also note that excessive logging itself can cause noticeable speed degradation. Likely cases are costly methods to provide data to your table view, custom heights perhaps? Or loading of content from a network synchronously.
Got the same problem. Just fixed it with barrym's comment. Just move the becaomeFirstResponder code to viewDidAppear
Hey guys, so in my newest program I use an NSTableView to display words on the left, and thier definitions on the right. these words and definitions are load from a .plist file, and at application startup the table view loads these words and definitions and displays them just fine. My problem comes in when the user tries to add a word and definition using the text boxes and buttons, the word is actually added to the .plist, meaning the method is running fine, but the table view refuses to display the new line. only until after i quit the program and reopen it does the tableview display the new line. I tested to see if the table view was connected properly by sending it other messages such as selectedRow and dataSource, all came back with responces, and proper responces at that. Currently the class that is used as the dataSource and delegate is a subclass to my main class with all my varibles and dictionaries. (I am big on using as little classes as possible). Lastly I tried inserting noteNumberOfRowsChanged in before reloadData, but still nothing.
I have tested everything and it just seems that the reloadData method is not initiating anything. Like I said, my table view is being sent the message, the new info is actually being added to the dicitinoary adn array, the amount of rows is being updated by the count method, and what proves it even more is that when the program is restarted it displays everything just fine. below is the relevent code, where currentWordList and currentDefitionList are the Array and Dictionary suppying the data to the dataSource, and editLibraryCardList is the NSTableView I am trying to reload.
the dataSource class code:
#interface EditorDataTable : SAT_Vocab_MacController {
IBOutlet NSTableColumn *editLibraryWordColumn;
IBOutlet NSTableColumn *editLibraryDefinitionColumn;
}
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
#end
#implementation EditorDataTable
- (int)numberOfRowsInTableView:(NSTableView *)tableView {
return ([currentWordList count]);
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
if (tableColumn == editLibraryWordColumn) {
return [currentWordList objectAtIndex:row];
}
if (tableColumn == editLibraryDefinitionColumn) {
return [currentDefinitionList valueForKey:[[currentWordList objectAtIndex:row]lowercaseString]];
}
}
#end
method that adds the word to the list:
- (IBAction) editLibraryAddWordToLibrary: (id) sender {
if (self = [super init]) {
currentWordList = [[NSArray alloc] initWithContentsOfFile:userSATWordListPath];
currentDefinitionList = [[NSDictionary alloc] initWithContentsOfFile:userSATDefinitionListPath];
}
[currentWordList addObject:[[editLibraryNewCardWordInput stringValue]capitalizedString]];
[currentDefinitionList setObject:[editLibraryNewCardDefinitionInput stringValue] forKey:[[editLibraryNewCardWordInput stringValue]lowercaseString]];
aWordCounter = [currentWordList indexOfObject:[[editLibraryNewCardWordInput stringValue]capitalizedString]];
[aWordLabel setStringValue: [[NSString alloc] initWithFormat:#"%#", [currentWordList objectAtIndex: aWordCounter]]];
[aDefinitionLabel setStringValue: [[NSString alloc] initWithFormat:#""]];
[currentWordList writeToFile:userSATWordListPath atomically:YES];
[currentDefinitionList writeToFile:userSATDefinitionListPath atomically:YES];
[cardCountdownNumber setStringValue: [[NSString alloc] initWithFormat:#"%i", ([currentWordList count] - (1 + aWordCounter))]];
[editLibraryCardList noteNumberOfRowsChanged];
[editLibraryCardList reloadData];
}
Iv'e been stuck for days and any ideas will help! Thanks.
Zach
Have you tried debugging into your selectRowAtIndexPath method to make sure the reload occurs? (after you call [tableView reloadData] should be able to see this) Are you using UITableViewController?
If you wanted a callback after reload to know when its done, you could try:
[tableView reloadData];
[self performSelector:#selector(selectRowAtIndexPath:) withObject:indexPath afterDelay:0.0];
For those who are curious, i moved my code from the dataSource subclass to the main class, and it worked. i guess you cannot subclass the dataSource. Hope this helps!