iPhone cellforrowatindexpath issue two nsarray - iphone

Here is my code below:
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
NSString *contentForThisRow = nil;
NSString *contentForThisRow2 = nil;
if (mySearchBar.text > 0)
{
contentForThisRow = [self.filteredListContent objectAtIndex:row];
NSInteger noWordIndex = [self.noWords indexOfObject:contentForThisRow];
contentForThisRow2 = [self.enWords objectAtIndex:noWordIndex];
NSLog (#"if success?");
}
else
{
contentForThisRow = [self.noWords objectAtIndex:row] ;
contentForThisRow2 = [self.enWords objectAtIndex:row];
NSLog (#"else success?");
}
static NSString *kCellID = #"cellID";
//standard code here etc for this method..
}
The codes above work perfectly except whenever I have used searchBar to filter and then click on Cancel button in the searchBar or Search button in the keyboard and then when I click on my custom "change" button in the navigationbar, the app crashes.
Before I use searchBar, there show up 4 NSLog after each change like:
2011-08-15 17:21:24.481 Enne1[4750:207] else success?
2011-08-15 17:21:24.483 Enne1[4750:207] else success?
2011-08-15 17:21:24.484 Enne1[4750:207] else success?
2011-08-15 17:21:24.485 Enne1[4750:207] else success?
And when I use searchBar to filter words, there show up also 4 NSLog like this:
2011-08-15 17:19:33.713 E1[4744:207] if success?
2011-08-15 17:19:33.714 E1[4744:207] if success?
2011-08-15 17:19:33.714 E1[4744:207] if success?
2011-08-15 17:19:33.715 E1[4744:207] if success?
But when after I have used searchBar and then cleared the searchText either with Cancel or Search and then click on "change button", there show up only 1 NSLog like this:
2
011-08-15 17:21:49.806 E1[4750:207] if success?
It should be
else success
in order to show the full lists, not
if success
.
Am I missing something?
EDIT 15 august:
I have tried
if(mySearchBar.text.length > 0)
as well, but the tableview shows nothing when I clear my search string and there came up only 2 nslogs, that is:
2011-08-15 23:49:06.624 E1[5064:207] if success?
2011-08-15 23:49:06.626 E1[5064:207] if success?
By the way, why does it show up 4 nslogs each time I enter one alphabet in the search bar? Shouldnt it show only one nslog each time?
And my codes for textDidChange is:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchString
{
NSLog (#" ss: %#", searchString);
if ([searchString length] == 0) {
[self performSelector:#selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
NSLog (#" searchstring: %#", searchString);
}
[self filterContentForSearchText:searchString];
[tableView reloadData];
NSLog (#"has reloaded!");
return;
}
Edit 15 august; This is wrong: I suspect the code above is causing the app crashing? not reloading tableview properly?
Am I right? NSLog for searchString showed nothing...
2nd edit 15 august: I added NSLog (#" ss: %#", searchString); and of course it shows alphabet(s) each time I enter one alphabet. So it must be something wrong with mySearchBar.text > 0, how should I write this properly?
By the way, I added tableview and searchbar programmatically, tableviews delegate and datasource is linked to self and searchbars delegate is linked to self as well. There is nothing in InterfaceBuilder, only UIView.

Not really sure what you're attempting with
if(mySearch.text > 0) {
//stuff
}
Looks, like you're trying to compare the length to see if the string is empty. Try using this instead:
if([mySearchBar text] == nil || ![[mySearchBar text] isEqualToString:#""]) {
//stuff
}
Getting into this code block is probably what the problem is. Not sure how your objects are implemented, but if the filtered list is nil, then you would crash trying to get objects from it and what not.

You should definitely use if(mySearchBar.text.length > 0), not if(mySearchBar.text > 0).
It probably crashes here:
contentForThisRow2 = [self.enWords objectAtIndex:noWordIndex];
because noWordIndex was -1 (i.e. 2147483647) in the previous line. It'll crash this way even if you just type in a word that doesn't exist in the noWords array, so you need to check if noWordIndex is >= 0 before using it to access enWords. This will probably fix the problem with cleaning the search text, too.
By the way, a much faster way to look up words would be using an NSDictionary instead of two arrays.

Ah, I solved it by adding length to mySearchBar.text; mySearchBar.text.length > 0 works. I forgot to rewrite in another method, I changed mySearchBar.text to mySearchBar.text.length, that is:
- (NSInteger)tableView:(UITableView *)tableView1 numberOfRowsInSection:(NSInteger)section
{
tableView1.rowHeight = 100 ;
tableView1.separatorColor = [UIColor colorWithRed:0.40 green:0.70 blue:0.45 alpha:1.0];
tableView1.opaque = NO;
if (mySearchBar.text.length > 0)
{
return [self.filteredListContent count];
NSLog (#"if return");
}
else
{
return [self.noWords count];
NSLog (#"else return");
}
}
#Daniel R Hicks
and
#ColdLogic: So both you are right that it is wrong to use only mySearchBar.text. Thank you very much for pointing me in the right direction.
But I still wonder why there come up 4 nslogs each time...
EDIT 16 august:
4 nslogs show up every time I launch the app, because there are 4 visible cells. My tableview.height is 100, so when I changed it to 50, 8 nslogs show up and as well as 8 visible cells.

Related

ReloadTable crashes app

This code causes the app to crash! I'm looping through a dictionary and everything logs out fine. It works when i write -1 in the for loop but not otherwise,
-(void)updateProjectTimes {
for(int i = 0; i < [projectsTable numberOfRowsInSection:0]-1; i++) {
NSString *currentValue = [[[projects objectForKey:#"activeProjects"] objectAtIndex:i] objectForKey:#"timepassed"];
NSString *finishValue = [[[projects objectForKey:#"activeProjects"] objectAtIndex:i] objectForKey:#"timeleft"];
if([currentValue intValue] < [finishValue intValue]) {
[[[projects objectForKey:#"activeProjects"] objectAtIndex:i] setObject:[NSString stringWithFormat:#"%d", ([currentValue intValue] + 1)] forKey:#"timepassed"];
} else {
[(NSMutableArray *)[projects objectForKey:#"activeProjects"] removeObjectAtIndex:i];
if([[projects objectForKey:#"activeProjects"] count] == 0) {
[projectTimer invalidate];
projectTimer = nil;
}
}
//[projectsTable reloadData]; works if i put it here!
}
[projectsTable reloadData]; //<- But not here!! :(
}
I assume you are wokring with tableView. Apparently you are modifing the data source of your tableView. When you remove an object from the data source, you have to adjust your tableView as well. Meaning either call reloadData, or call [tableView deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation].
The reason your app doesn't crash if you put -1, could be -- perhaps -- because there is only on item that matches the [currentValue intValue] < [finishValue intValue] condition, so that if you go through [projectsTable numberOfRowsInSection:0]-1, after removing that object, numberOfRowsInSection matches the count of projectsTable.
But it is good only for one cycle. When the next cycle happens, in the if...loop, you app crashes again, unless you include the [projectsTable reloadData] in the same if...loop.
While the reloadData method works just fine, but if you are simply removing a row, or adding a row to your table by adding or removing objects, its better to use deleteRowsAtIndexPaths or insertRowsAtIndexPaths methods. There will be less overhead and work for your app, and would make it smoother and faster.
The bottom line, to make your code work, right after [(NSMutableArray *)[projects objectForKey:#"activeProjects"] removeObjectAtIndex:i]; remove the corresponding object from your tableView by calling deleteRowsAtIndexPaths.
Alternatively, you can also use beginUpdates and endUpdates. For a complete reference, refer to http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html
Hope it helps.

Show UIAlertView if UITableView is empty

I have RSS, and the UITableView loads data from it, how can I show UIAlertView if the UITableView is empty, but not by count of an array because the array is different every time it is refreshed, is there some kind of function which will check if UITableView is empty after it completes drawing?
You can query the UITableView itself. So assuming you have a single section you could do the following ...
// Reload the tableview
[tableView reloadData];
// Test the number of rows in the first section
if ([tableView numberofRowsInSection:0] == 0) {
// Display UIAlertView here
}
EDIT; Based on the comments below ...
In your header file (.h) iVar declarations ...
int feedCount;
int feedsParsed;
In your implementation ...
- (void)refresh {
feedCount = 0;
feedsParsed = 0;
[feedParser stopParsing];
self.title = #"Refreshing...";
[parsedItems removeAllObjects];
for (NSString *imePredmeta in [Data variables].mojiPredmeti) {
... // I've removed these lines for brevity but they are still required
[feedParser parse];
feedCount += 1;
}
// Delete everything else after this line
}
- (void)feedParserDidFinish:(MWFeedParser *)parser {
feedsParsed += 1;
if (feedsParsed == feedCount) {
[self.tableView reloadData];
if ([self.tableView numberofRowsInSection:0] == 0) {
// Fade out tableview and display alert here as we now know for
// sure that there are no more feeds to parse and we definitely
// have nothing to display
}
}
}
You will need to loop round the array and check to determine if there are no results.
Please post your existing tableview code if you want a more explicit answer.
edit: micpringle answer above is better.

Changing number of different UITableViewCells with particular order like Calendar app

Sorry for the long title. In essence, I want to accomplish the same thing that the Calendar app does for Event details.
The first cell shows the title and date of the event. The second shows an alert, if there is one, otherwise Notes, if there are any, or nothing else if none of these fields is present.
The way I am doing it now is a really long if condition in cellForRowAtIndexPath:
if(indexPath.row == 0) {
TitleCell *titlecell = [[TitleCell alloc] init];
// config cell to do title here, always
return titlecell;
} else if (indexPath.row == 1 && foo) {
FooCell *foocell = [[FooCell alloc] init];
// config cell to show foo, if it exists
return foocell;
} else if (indexPath.row == 1 && bar) {
BarCell *barcell = [[BarCell alloc] init];
// foo doesn't exist, but bar, so show bar in cell 1
return barcell;
} // etc etc
That's really ugly, and since I create the cells in the if and return, the static analyzer tell me that each one of those is a potential leak. There is no else, since I need to cover all scenarios anyway, and that also gives a warning about the method potentially not returning anything.
Is there a better way that makes this cleaner and doesn't give me warnings?
Thanks!
Christoph
The warning are because you are leaking memory, you have to autorelease the cell: TitleCell *titlecell = [[[TitleCell alloc] init] autorelease];. Also there is a chance of not having a return statement because you don't have else in your if block.
Here is another way of doing it:
// Call this beforehand
- (void)loadTable {
// Since we are not using objects, we need to use a non-retaining array
// A better way of doing this would be with delegates or NSInvocations
array = (NSMutableArray*)CFArrayCreateMutable(NULL, 0, NULL);
[array addObject:(id)#selector(buildTitleCell)];
if (foo)
[array addObject:(id)#selector(buildFooCell)];
if (bar)
[array addObject:(id)#selector(buildBarCell)];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < array.count) {
SEL selector = (SEL)[array objectAtIndex:indexPath.row];
return [self performSelector:selector];
}
return nil;
}
- (UITableViewCell*)buildTitleCell {
TitleCell *titlecell = [[[TitleCell alloc] init] autorelease];
// config cell to do title here, always
return titlecell;
}
...
EDIT: fixed as per #Christoph's comment
Clang is right when it says that you're leaking memory - The UITableView retains the UITableViewCells that you give it, so you should be autoreleasing them in cellForRowAtIndexPath.
Instead of using if statments, I think you should be using a switch.

searchdisplaycontroller: change the text of the searchbar

SHORT DESCRIPTION OF PROBLEM:
I want to set the text of a searchbar without automatically triggering the search display controller that is bound to it.
LONG DESCRIPTION OF PROBLEM:
I have an iphone application with a search bar and a search display controller. The searchdisplaycontroller is used for autocomplete. For autocomplete i use an sqlite database. The user enters the first few letters of a keyword and the result are shown in the table of the searchdisplaycontroller. An sql select query is executed for every character typed. this part works ok, the letters have been entered and the results are visible.
The problem is the following: If the user selects a row from the table I want to change the text of the searchbar to the text that was selected in the autocomplete results table. I also want to hide the search display controller. This is not working. After the search display controller disappears the textbox in the search bar is empty. I have no idea what's wrong. I didn't think something so simple as changing the text of a textbox can get so complicated.
I have tried to change the text in 2 methods:
First in the didSelectRowAtIndexPath method (for the search results table of the search display controller), but that didn't help. The text was there while the search display controller was active (animating away) but after that the textbox was empty.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath");
if (allKeywords.count > 0)
{
didSelectKeyword = TRUE;
self.selectedKeyword = (NSString *)[allKeywords objectAtIndex: indexPath.row];
NSLog(#"keyword didselectrow at idxp: %#", self.selectedKeyword);
shouldReloadResults = FALSE;
[[self.mainViewController keywordSearchBar] setText: selectedKeyword];
//shouldReloadResults = TRUE;
[[mainViewController searchDisplayController] setActive:NO animated: YES];
}
}
I also tried to change it in the searchDisplayControllerDidEndSearch method but that didn't help either. The textbox was...again.. empty.
edit: actually it wasnt empty the text was there but after the disappearing animation the results of the autocomplete table are still there. So it ends up getting worse.
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
NSLog(#"searchDisplayControllerDidEndSearch");
if (didSelectKeyword)
{
shouldReloadResults = FALSE;
NSLog(#"keyword sdc didendsearch: %#", selectedKeyword);
[[mainViewController keywordSearchBar] setText: selectedKeyword]; //
In this method i call another method which selects the data from sqlite. This part is working.
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
NSLog(#"shouldReloadResults : %i", shouldReloadResults);
if (shouldReloadResults)
{
NSLog(#"shouldReloadTableForSearchString: %#", searchString);
[self GetKeywords: searchString : #"GB"];
NSLog(#"shouldReloadTableForSearchString vege");
return YES;
}
return NO;
}
Please ask me if it's not clear what my problem is. I need your help. Thank you
Didn't you try :
mainViewController.searchDisplayController.searchBar.text=selectedKeyword;
You access the search bar field from the search controller and you update its text content.
Now it works i don't know what happened. I think I tried to deactivate the search display controller after changing the text. Anyway thanks for help. I think I also tried to change the original textfield not the one belonging to the search display controller and they are different (different adresses in memory as far as i observed)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSLog(#"didSelectRowAtIndexPath");
if (allKeywords.count > 0)
{
didSelectKeyword = TRUE;
self.selectedKeyword = (NSString *)[allKeywords objectAtIndex: indexPath.row];
NSLog(#"keyword didselectrow at idxp: %#", self.selectedKeyword);
//shouldReloadResults = FALSE;
[[mainViewController searchController] setActive:NO animated: YES];
[mainViewController.searchController.searchBar setText: self.selectedKeyword];
}
}

Why does this only work sometimes? (UITextView resign first responder question)

When a user presses the "SEND"(return) button I want the keyboard to retract and do other stuff like send a message. But it only works SOMETIMES...
Why does this code only work SOMETIMES? I need it to work all the time obviously, but it doesn't.
- (void)textViewDidChange:(UITextView *)inTextView {
NSString *text = myTextView.text;
if ([text length] > 0 && [text characterAtIndex:[text length] -1] == '\n') {
myTextView.text = [text substringToIndex:[text length] -1];
[myTextView resignFirstResponder];
[self sendMessage];
}
}
It only gets called if
([text length] > 0 && [text characterAtIndex:[text length] -1] == '\n')
is true. Is this always the case? Maybe add an NSLog statement outside and inside the state to see if it is indeed true all of the time.
Checking for \n looks bizarre. Why would you do that?
This method is getting passed in a view called inTextView but inside the method you are referring to myTextView and you don't mention where that got set.
I would suggest that you change all the myTextView references to inTextView and see if that resolves the problem as you may be working on a UITextView other than myTextView and seeing your problems because of that.