How to populate tableview controller with text input - ios

I have created a table view controller with a UITextField on it. How can I populate the tableview controller cell of the input text that came from the UITextField. I tried the following but it seems the array is empty or being emptied
- (IBAction)endingInput:(id)sender{
[sender resignFirstResponder];
//send the message to the table cell
NSMutableArray *history = [[NSMutableArray alloc] init];
[history addObject:[NSString stringWithFormat:#"%#",self.chatMessageField.text]];
[self.chatHistory addObject:history];
[myTableView reloadData];
//push the message to server
[self initiateMessageSending:self.chatMessageField.text];
chatMessageField.text = #"";
[history release];
}
On my cellForRowAtIndex method;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(tableView == self.myTableView){
cell.textLabel.text = [chatHistory objectAtIndex:indexPath.row];
}
return cell;
I have set a break point but it doesn't pass there. I suspect my array is empty.
Likewise, where is the best place to call the reloadData method?
Also, chatHistory is private member, is there a way to initialize it like [[self.chatHistory alloc] init]; ?
I know its a common question but I've been haggling with this for sometime now.

I think you have forgotten to alloc and init your chatHistory
- (void)viewDidLoad
{
self.chatHistory = [[NSMutableArray alloc] init];
}

If you aren't initializing chatHistory it doesn't even exist...never mind being empty! (I'm not clear what "private member" means here.)
If you log the value of chatHistory, you'll see for sure whether it is nil or empty.
The other problem I see is that you're trying to load chatHistory with other (history) arrays but then use its content as a string. You should decide whether it's going to be an array of arrays or an array of strings and then stay consistent.
(Also [[self.chatHistory alloc] init]; isn't valid syntax for creating a new object. Look at an Objective-C language reference for the right way.)

Related

Is proper practice to use introspection in this example?

Is proper practice to use introspection in this example?
I'm in a UITableView datasource method tableView:cellForRowAtIndexPath:, and I'm checking for the type of the data source objects, in order to decide which UITableViewCell subclass to use.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
id object = [[self getDataSource:tableView] objectAtIndex:[indexPath section]];
if ( [object isKindOfClass:[NSString class]] ||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else if ([object isMemberOfClass:[NSNumber class]]) {
cell = [[[CMAutocompleteTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier andAutocompleteTextField:object] autorelease];
} else if ([object isMemberOfClass:[NSDate class]]) {
cell = [[[CMDateTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier andTextView:object] autorelease];
} else {
cell = [[[CMAutocompleteTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier andAutocompleteTextField:field] autorelease];
}
return cell;
}
I can't see any reason not to check the classes of your data objects, but you should use isKindOfClass: rather than isMemberOfClass:.
The latter checks for an exact match with the class of the receiver, which you're not going to get with the data classes you've got; they're all class clusters. Any given NSString you have, e.g., is going to actually be an __NSCFString. Likewise for NSDate and NSNumber.
Also, you should use ARC.
It's technically ok (with the change to isMemberOfClass: as Josh pointed out).
It's debatable, if it's good style. Does the same tableview really show items of those different classes next to each other? If there are several tableviews, using separate methods/delegates might be more appropriate.
Also, I think you could improve on your method naming. getDataSource is discouraged - "get" has quite a special meaning and is rarely used (for example, in getBytes on NSData). Also you want to get rid of "and" which is just noise.
Finally, is there any reason not to switch to ARC today?

UITableView not reloading correctly

I've been having this problem a lot where the table view either doesn't load the cells the first time or displays temporary labels. In both cases, when the table is loaded a second time (by another button in which I force it to reload or by going to the previous view in the app and going back to the table) everything shows up as it was supposed to.
Im using [table reloadData] to reload the table in the viewDidAppear: method as it didn't work in the viewDidAppear: method and in another case I put it in a button action.
I'm also using this method to set the label of the cell that I have placed in the storyboard:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [contactsTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *label = (UILabel *)[cell viewWithTag:1001];
label.text = [Array3 objectAtIndex:indexPath.row];
return cell;
}
EDIT
I declare the array below the implementation like:
NSMutableArray * Array3;
After that in the ViewDidLoad method I declare the rest of the array:
Array3 = [NSMutableArray arrayWithObjects: nil];
Then I load the elements in the array by calling a function within the ViewDidLoad method to fill the array with elements.
EDIT 2
Showing more of how I populate the array
- (void)viewDidLoad {
[super viewDidLoad];
Array3 = [NSMutableArray arrayWithObjects: nil];
[self loadArray];
}
- (void) loadArray
//populate array in here.
// I use the add object method
// [Array3 addobject:object];
{
Good news first: Your method cellForRowAtIndexPath is correct.
There is no need to invoke reloadData in neither -viewDidAppear: nor -viewWillAppear. This remark may not hold true if you modify the content of Array3 while your view is covered, which is a special case.
It is not a matter of where you define your method, but where you invoke it. A reasonable place to populate the content of Array3 is in
required init(coder aDecoder: NSCoder!)
or
override func viewDidLoad()
Pitfalls
Additionally, you need all your delegate methods (numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath) to be returning consistent values, in accordance to your array. A simple technique is to use the number of entries in the array to drive numberOfRowsInSection.
When to use reloadData?
A typical use of reloadData is shown below:
- (void)loadArray {
//populate array in here.
...
[self.tableview reloadData]; // Possibly postpone to main thread
}
Give the cell identifier unique for example you can
NSString *cellIdentifier =[NSString stringWithFormate:#"%d",indexPath.row];
Maybe this will help you...
I think the Array3 is nil When the first load.
I believe that in your initial set up for Array3 you must allocate this variable to memory to then be used in a different function, like the tableView:cellForIndexPath:
Therefore instead of Array3 = [NSMutableArray arrayWithObjects: nil]; you would use Array3 = [[NSMutableArray alloc] init];
Since you're leaving it as an empty array on this line of code, you would not use [[NSMutableArray alloc] initWithObjects: nil]; because it is literally the same deal

Need to set reuseIdentifier, but not possible

my App is kind of a FileManager like the Finder under MAC OS. I can show up the root of the filesystem. But the Navigation through the directories makes problems.
In the method didSelectRowAtIndexPath i create a new instance of the current TableViewController. I set the Delegate and DataSource toself. Now the Problem that i have: The TableViewCells of the new created instance do not have a resueIdentifier. The value is NULL. And i cant set it because its read-only. So, how can i get the new cells to have a specific reuseIdentifier?
Below is my Code from the didSelectRowAtIndexPath- Method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryDisclosureIndicator)
{
NSLog(#"Entered Directory");
NSLog(#"reuseIdentifier: %#",cell.reuseIdentifier); // <- value: "fileCell"
FileTableViewController *newDir = [[FileTableViewController alloc] init];
newDir.tableView.dataSource = self;
newDir.tableView.delegate = self;
[newDir setDirectory:cell.textLabel.text];
UITableViewCell *newCell = [newDir.tableView cellForRowAtIndexPath:indexPath];
NSLog(#"reuseIdentifier NewCell: %#",newCell.reuseIdentifier); // <- is NULL
//[newDir setTitle: [fileManager currentDirectoryPath]];
/*[self setDirectory:cell.textLabel.text];
self.title = [NSString stringWithFormat:#"%#", [fileManager currentDirectoryPath]];
[self.tableView reloadData];
*/
[self.navigationController pushViewController:newDir animated:YES];
}
}
if you need more Code to help me, just let me know.
Thanks, Chris
Maybe I'm too late with this answer. But here're my thoughts.
UITableViewCell *newCell = [newDir.tableView cellForRowAtIndexPath:indexPath];
NSLog(#"reuseIdentifier NewCell: %#",newCell.reuseIdentifier); // <- is NULL
It is NULL because the tableView is not created. It will be created just after you make a push.
If you want to pass some params to your table, you should implement the variables in the FileTableViewController.h, and then in your didSelectRowAtIndexPath make use of this like:
FileTableViewController *newDir = [[FileTableViewController alloc] init];
newDir.SomeData = cell.textLabel.text;
One more important thing - if the FileTableViewController is a UITableViewController, you should not set the dataSource and delegate, especially in your current viewController. Because doing this, you set delegate to self of current viewController (not the FileTableVC that was created).
Otherwise, if FileTableVC is not UITAbleViewController Class, you should make the delegate and datasource in FileTableVC's viewDidLoad.

How to skip a specific string when populating my UITableView

I am populating a tableview from data that is received from a server. The data is a list of user activities within a given timeframe. One such activity is "Login". I do not wish to populate my tableview with this string but I'm not sure how to skip it when populating my tableview.
Here is how I populate the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
#try{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if ([action isEqualtoString:#"Login"]) {
return cell;
}
return cell;
}#catch (NSException *ex) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
}
As you can see I tried using return cell but as you probably know it gives me a blank cell when the table is displayed. I'm sure there is a simple line of code for this but I came up blank with the search terms I used. Could someone please enlighten me! Thanks!
P.S. you may be thinking I am not putting anything in any of the cells but I pulled out a bunch of code to keep this short.
UPDATE:
Thanks for the heads up on "isEqualtoString:" Everything worked fine with "isEqual" but I changed it given that I received so many suggestions to do so. But this is not what I am asking.
To be more clear if I had an array containing the terms: view, view, login, view. When my tableview was populated I would have 4 cells that said; view, view, login, view. I simply want to ignore the term login so that I would have 3 cells that all said view. Thanks!
There can be many way to do this.
I Belive that UITabelView should display what its datasource (here datasource is self.fetchedResultsController) contains.
What you can do is create another NSArray from self.fetchedResultsController which does not contain this object.
Try this:
NSMutableArray *newSource = [[NSMutableArray alloc] init];
for(int i = 0; i < self.fetchedResultsController.count ; i++)
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if (![action isEqual:#"Login"])
{
[newSource addObject:action];
}
}
[tableView reloadData];
Now use newSource instead of self.fetchedResultsController
You might think that using one more array is not good. But believe it it is far easier than using the same array with condition. You don't have to worry about that condition when you perform some operation with your UITableView like remove object by using indexpath.
try using if ([action isEqualToString:#"Login"])
When you want to compare strings you need to use this isEqualToString .
Change this line
if ([action isEqualToString:#"Login"]) {
return cell;
}
You are using the wrong function to compare your input string and the given data variable.
They both are NSString objects so use :
if([action isEqualToString:#"Login"])
{
//enter your code here
}
#Ben : I am assuming that you have registered you cell through nib as you are using dequeueReusableCellWithIdentifier.
Make your tableview content as "Dynamic prototype" (You can see this in Attributes Inspector of table view) and change your table view cell style as custom (You can see this in Attributes Inspector of tableview cell).

Selecting Variable Dynamically

Hello and thank you for your time. Im fairly new to IOS/Objective C.
I have multiple variables setup globally at the top of my viewcontroller.
NSMutableArray * A;
NSMutableArray * B;
NSMutableArray * C;
Now when someone selects a cell in a tableview I would like to use the name of that cell to select one of the global variables. I found something for doing this with viewcontrollers, but I need something for misc variables as well. I am reffering to:
id myNewController = [[NSClassFromString(selected) alloc] init];
[[self navigationController] pushViewController:myNewController animated:YES];
So it would be something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Save text of the selected cell:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
stringVariable = cell.textLabel.text;// value=A,B or C
// match string to array and load that array.
??
}
Thanks in advance for any help, and sorry if this has been asked but I couldn't find anything that worked so as a last resort im asking for help :)
You may be better off storing your arrays as keys on a dictionary, instead of as individual fields. For example:
NSDictionary* dictionary;
dictionary = #{
#"A": [[NSMutableArray alloc] init],
#"B": [[NSMutableArray alloc] init],
#"C": [[NSMutableArray alloc] init]
};
Then when your row is selected, you could lookup the array by key:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString* key = cell.textLabel.text;// value=A,B or C
NSMutableArray* array = dictionary[key];
....

Resources