function to check if there is any empty cell in a multicolumn nstableview not working - objective-c

Hi i have written a function to check if there is any empty cell in a multicolumn nstableview like below.However this function is not working and always checks for the columns in the first row only.. any suggestions.and what is the right way to check for it
-(BOOL)isTableRowsContainingEmptyCells
{
for(int row=0;row< [[self.myarray arrangedObjects] count];row++)
{
NSTableColumn *column1 = [self.formFieldValues
tableColumnWithIdentifier:#"A"];
NSTableColumn *column2 = [self.formFieldValues
tableColumnWithIdentifier:#"B"];
NSCell *cell1 = [column1 dataCellForRow:row];
NSCell *cell2 = [column2 dataCellForRow:row];
NSLog(#"cell1 %# cell2 %#",cell1,cell2);
if([[cell1 stringValue] isEqualToString:#""]||[cell1 stringValue]==nil||[[cell2 stringValue] isEqualToString:#""]||[cell2 stringValue]==nil)
{
return YES;
}
}
return NO;
}

Try like this
NSCell *cll=[tableView preparedCellAtColumn:0 row:0];
NSString *str=[cll stringValue];
NSInteger len=[str length];
if (len ==0)
{
NSLog(#"NO data")
}

Related

Implementing copy method - copy whole row

I am trying to copy the row of the NSTableView on clipboard. Here is my code:
- (void) copy:(id)sender
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
// I get warning in the line bellow, unused variable changeCount
NSInteger changeCount = [pasteboard clearContents];
NSInteger row = [self.customersViewController.customersTableView selectedRow];
NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:#"firstName"];
NSCell *cellFirstName = [columnFirstName dataCellForRow:row];
NSArray *objectsToCopy = #[[cellFirstName stringValue]];
// I get warning in the line bellow unused variable OK
BOOL OK = [pasteboard writeObjects:objectsToCopy];
}
This code works, and if I select the row in the NSTableView, the content of the firstName column of the selected row is indeed on the pasteboard (I can paste the value in text editor).
However this code have couple of issues:
1. I get 2 warnings as you can see from my comments.I rewrite the code to get rid of the warnings like this. Is anything wrong with the way how I re-write the code?
// warning one
NSInteger changeCount = 0;
changeCount = [pasteboard clearContents];
// warning 2
BOOL OK = NO;
OK = [pasteboard writeObjects:objectsToCopy];
In the code above I name specific which NSTableView I use
...self.customersViewController.customersTableViev....
However If the user switch the view, it may use some other NSTableView...how can I find out from which NSTableView the copy method should copy the row?
If I comment the line where I use specific NSTableView and try to use sender, my app crashes.
//NSInteger row = [self.customersViewController.customersTableView selectedRow];
NSInteger row = [sender selectedRow];
3.How could I write a loop to get all column names instead of specifically write them by hand one by one? I will not know which NSTableView is used anyway....
NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:#"firstName"];
If you don't want the return value you can omit it.
To make you code table view independent you can use firstResponder of the window. Alternatively you can implement copy: in a cubclass of NSTableView. sender is the menu item.
NSTableView's property tableColumns is an array of NSTableColumn.
Here's what I did:
- (void)copy:(id)sender {
NSResponder *firstResponder = self.window.firstResponder;
if (firstResponder && [firstResponder isKindOfClass:[NSTableView class]]) {
NSTableView *tableView = (NSTableView *)firstResponder;
NSArrayController *arrayController = [[tableView infoForBinding:NSContentBinding] objectForKey:NSObservedObjectKey];
// create an array of the keys and formatters of the columns
NSMutableArray *keys = [NSMutableArray array];
for (NSTableColumn *column in [tableView tableColumns]) {
NSString *key = [[column infoForBinding:NSValueBinding] objectForKey:NSObservedKeyPathKey]; // "arrangedObjects.name"
if (key) {
NSRange range = [key rangeOfString:#"."];
if (range.location != NSNotFound)
key = [key substringFromIndex:range.location + 1];
NSFormatter *formatter = [[column dataCell] formatter];
if (formatter)
[keys addObject:#{#"key":key, #"formatter":formatter}];
else
[keys addObject:#{#"key":key}];
}
}
// create a tab separated string
NSMutableString *string = [NSMutableString string];
for (id object in [arrayController selectedObjects]) {
for (NSDictionary *dictionary in keys) {
id value = [object valueForKeyPath:dictionary[#"key"]];
if (value) {
NSFormatter *formatter = [dictionary objectForKey:#"formatter"];
if (formatter)
[string appendFormat:#"%#\t", [formatter stringForObjectValue:value]];
else
[string appendFormat:#"%#\t", value];
}
else
[string appendFormat:#"\t"];
}
[string replaceCharactersInRange:NSMakeRange([string length] - 1, 1) withString:#"\n"];
}
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard setString:string forType:NSPasteboardTypeString];
}
}

How to retrieve kABPhoneNumber from Address Book in Cocoa with multiValues?

I'm trying to extract phone numbers from an ABRecord and put it into a NSTableView. It logs the number, but the app crashes when the tableView is scrolled and tries to get more data. Is the way I'm retrieving the number the right way to do so? Its not clear to me why it sometimes fails to load it into the cell.
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
contactCell *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if( [tableColumn.identifier isEqualToString:#"cell"] )
{
ABPerson *indexedPerson = contactsArr[row];
ABRecord *record = contactsArr[row];
NSString *numberString = #"";
NSString *nameInfo = [NSString stringWithFormat:#"%# %#",
[indexedPerson valueForKey:kABFirstNameProperty],
[indexedPerson valueForKey:kABLastNameProperty]];
//get the number
ABMutableMultiValue *multiValue = [record valueForProperty:kABPhoneProperty];
NSLog(#"currentPerson: %#",indexedPerson);
//see if there is data in the multi value
if ([multiValue valueAtIndex:1]) {
numberString = [multiValue valueAtIndex:1];
} else {
numberString = #"";
}
NSLog(#"%# test", numberString);
//set the strings
[cellView.nameField setTitle:nameInfo];
//set field in cell
[cellView.numberField setTitle:numberString];
return cellView;
}
return cellView;
}
Instead of checking index 0, I was checking index 1. Changing to index 0 in the if statement checking for data in the multivalue resolved the issue.

search method not working after second hit

I've a problem with my UISearchDisplayController, the search is not working properly.
This is my code:
- (void)filterContentForSearchText:(NSString*)searchText
scope:(NSString*)scope
{
[self.searchResults removeAllObjects];
for (int i = 0; i < [temp_category count]; i++) {
BOOL foundResult = FALSE;
if ([[temp_category objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_producttitle objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_type objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_description objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if (foundResult) {
NSNumber *result = [NSNumber numberWithInt:i];
if ([self searchResults] == nil) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release];
}
[searchResults addObject:result];
}
}
NSLog (#"array = %i", [searchResults count]);
NSLog(#"%#",searchResults);
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterContentForSearchText:[self.searchDisplayController.searchBar text]
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:searchOption]];
return YES;
}
But I'm still confused, because when I start a search with the first letter, it gives the correct hits. But when I enter the second letter, it only shows one result (while there are more, as far as I know from my data sample). I'm doing something incorrectly. I think it has something to do with when the user enters text, but I'm confused which method I should use.
The code I now have is a combination of:
this tutorial and
this SO question.
Can someone give me a hint in the good direction? Displaying the results is fine, only this aspect bothers me. I think it has something to do with firing the method and [self.searchResults removeAllObjects];.
I would like to add my code, but the thing is that I still use the code I have above, but I'm manually implementing the UISearchBar (which I found somewhere else in a tutorial) instead of using SearchDisplayController. I also had difficulties with the navigationbar which dissappears when using SearchDisplayController, which gave me enough reason to implement it myself instead of using SearchDisplayController. It gives you more freedom.
At first it seemed a lot of work, so I choose to use SearchDisplayController, but I really advise anyone who needs some modification, or who wants more freedom, please do it manually with UISearchBar and a UITableView :)

Setting reuseIdentifier on storyboard causes custom UITableViewCell to not be displayed

When attempting to load a custom UITableViewCell from a nib, I am unable to get the cell to appear only if I have set the reuseIdentifier on the prototype cell in the main storyboard. If this is set to blank, I get a warning from xcode, however the code runs correctly. I have similar code in several other controllers, however this is the only one presenting this issue.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"AssetsTableCell";
AssetsTableCell *assetTableCell = (AssetsTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
int rightIndex = (indexPath.row * 4);
int rightMiddleIndex = (indexPath.row * 4) + 1;
int leftMiddleIndex = (indexPath.row * 4) + 2;
int leftIndex = (indexPath.row * 4) + 3;
if (assetTableCell == nil) {
NSArray *topLevelObjects;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"AssetsTableCell_iPhone" owner:nil options:nil];
assetTableCell = (AssetsTableCell *)[topLevelObjects objectAtIndex:0];
[assetTableCell setDelegate:self];
}
// Need to collect the badge details in groups of 4.
#try {
NSArray *rowArray = [NSArray arrayWithObjects:[remoteContainers objectAtIndex:rightIndex],
[remoteContainers objectAtIndex:rightMiddleIndex],
[remoteContainers objectAtIndex:leftMiddleIndex],
[remoteContainers objectAtIndex:leftIndex],
nil];
NSDictionary *cellData = [NSDictionary dictionaryWithObjectsAndKeys:
[rowArray objectAtIndex:0], #"LEFT_CONTAINER",
[rowArray objectAtIndex:1], #"LEFT_MIDDLE_CONTAINER",
[rowArray objectAtIndex:2], #"RIGHT_MIDDLE_CONTAINER",
[rowArray objectAtIndex:3], #"RIGHT_CONTAINER", nil];
[assetTableCell populateCellData:cellData];
}
#catch (NSException *exception) {
DLog(#"Exceeds boundary of remoteContainers array by %d.", ([remoteContainers count] % 4));
int remainder = [remoteContainers count] % 4;
switch (remainder) {
case 1: {
// Check to see the number of remaining containers left in the rest of the array. This dictates the way the final row must be constructed.
if ([remoteContainers objectAtIndex:currentStartRangeIndex]) {
NSDictionary *cellData = [NSDictionary dictionaryWithObjectsAndKeys:[remoteContainers objectAtIndex:rightIndex], #"LEFT_CONTAINER", #"EMPTY_CELL", #"LEFT_MIDDLE_CONTAINER", #"EMPTY_CELL", #"RIGHT_MIDDLE_CONTAINER", #"EMPTY_CELL", #"RIGHT_CONTAINER", nil];
[assetTableCell populateCellData:cellData];
}
}
break;
case 2: {
// There are two elements at the end of the array.
NSDictionary *cellData = [NSDictionary dictionaryWithObjectsAndKeys:[remoteContainers objectAtIndex:rightIndex], #"LEFT_CONTAINER", [remoteContainers objectAtIndex:rightMiddleIndex], #"LEFT_MIDDLE_CONTAINER", #"EMPTY_CELL", #"RIGHT_MIDDLE_CONTAINER", #"EMPTY_CELL", #"RIGHT_CONTAINER", nil];
[assetTableCell populateCellData:cellData];
}
break;
case 3: {
// There are three elements at the end of the array.
NSDictionary *cellData = [NSDictionary dictionaryWithObjectsAndKeys:[remoteContainers objectAtIndex:rightIndex], #"LEFT_CONTAINER", [remoteContainers objectAtIndex:rightMiddleIndex], #"LEFT_MIDDLE_CONTAINER", [remoteContainers objectAtIndex:leftMiddleIndex], #"RIGHT_MIDDLE_CONTAINER", #"EMPTY_CELL", #"RIGHT_CONTAINER", nil];
[assetTableCell populateCellData:cellData];
}
break;
default: {
DLog(#"Thought the array had more elements, however was unable to determine the number of elements remaining in array.");
}
break;
}
}
}
return assetTableCell;
}
It looks like you configure each cell only in the case where the tableView cannot dequeue a cell for you. For one thing, your cell reuse is probably broken as a result. So that's one issue.
And then in the case of the storyboard, if the cell identifier is set correctly then the [tableview dequeueReusableCellWithIdentifier:] will always return a cell for you. So assetTableCell will not be nil, even the first time.
It's not clear exactly what all your logic is here, but you need to be able to properly set the content of your cell in the case where assetTableCell is not nil. (either because the cell is being recycled or because the cell came from the storyboard cache)

cancel button on search bar does not cancel correctly

I have a search bar, i can search now, but when I enter a text to search, and click the cancel button. It does not give me back my first stage, meaning full of the items in the table.
For example: I search the item with word: a, it gives me all the a items, yes, it is right now, but when i hit the cancel button, i want the programme gives me all the items exist, not just a items.
Here is the code: please help me out. Thank you so much.
- (void)searchBarCancelButtonClicked:(UISearchBar *)aSearchBar
{
searchBar.text = #"";
[searchBar resignFirstResponder];
letUserSelectRow = YES;
searching = NO;
self.tableView.scrollEnabled = YES;
NSLog(#"what text after cancel now: %#", searchBar.text);
[self.tableView reloadData];
}
- (NSMutableArray *) searchTableView {
NSString *searchText = searchBar.text;
NSLog(#"search text: %#", searchText);
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSMutableArray *tempArr = [[NSMutableArray alloc] init];
for (NSDictionary *dTemp in arrayData)
{
NSString *tempStr = [dTemp objectForKey:#"url"];
NSLog(#"sTemp string: %#",[ NSString stringWithFormat:#"%#", tempStr]);
NSRange titleResultsRange = [tempStr rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
{
NSLog(#"1 count :%d", [resultArray count]);
[resultArray addObject:dTemp];
NSLog(#"2 count :%d", [resultArray count]);
[tempArr addObject:resultArray];
[resultArray release];
resultArray = [NSMutableArray new];
}
}
if (resultArray != nil) {
[resultArray release];
}
return tempArr;
}
- (void)searchBar:(UISearchBar *)aSearchBar textDidChange:(NSString *)searchText
{
NSLog(#"what text after cancel now: %#", searchBar.text);
if([searchText length] > 0) {
[sortedArray removeAllObjects];
searching = YES;
letUserSelectRow = YES;
self.tableView.scrollEnabled = YES;
NSMutableArray *searchArray = [self searchTableView];
sortedArray = [[NSMutableArray alloc] initWithArray:searchArray copyItems:YES];
for (int i = 0; i<[sortedArray count]; i++) {
NSLog(#"this is the search array: %#", [[sortedArray objectAtIndex:i] class]);
}
NSLog(#"sorted array: %d", [sortedArray count]);
}
else {
searching = NO;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
You don't need to override any of UISearchBar methods to accomplish this. The new way of doing this relies on the UISearchDisplay controller instead (specifically on shouldReloadTableForSearchString).
Declare your view controller to conform to UISearchDisplayDelegate protocol, and keep two instance variables: your model as NSArray (all data) and a filtered array as NSMutableArray (a subset of your data). The code you presently have in "searchTableView" would filter the content of the model and place it into the filtered NSMutableArray. Then you would override the following UITableView methods: -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. In each, before returning, make a comparison to determine whether your tableView argument is equal to self.searchDisplayController.searchResultsTableView. If it is, the user is looking at the filtered list and your should use the content of the filtered NSMutableArray to create the view, otherwise, the user is looking at the whole data set and you should use the content of the NSArray that holds your model. Take a look at the following Apple code for a simple example of what I described:
http://developer.apple.com/library/ios/#samplecode/TableSearch/Introduction/Intro.html