Three20 TTTableViewController and searchViewController - iphone

I am trying to implement adding recipients to TTMessageController based on the example from TTCatalog.
Everything works fine until I enter search controller - I can search and get results, but nothing happens when I select items. I tried to set delegates, but none works.
- (void)loadView {
[super loadView];
TTTableViewController* searchController = [[TTTableViewController alloc] init];
searchController.dataSource = [[FriendsDataSource alloc] initWithApi:self.appDelegate.api];
searchController.variableHeightRows=YES;
self.searchViewController = searchController;
self.tableView.tableHeaderView = _searchController.searchBar;
}
In TTCatalog, items in search have an URL directing to google - that's not very helpful ;)

OK, I've found the answer :)
One line was missing from the code above. I had a feeling I should set the delegate, but didn't know where:
- (void)loadView {
[super loadView];
TTTableViewController* searchController = [[TTTableViewController alloc] init];
searchController.dataSource = [[FriendsDataSource alloc] initWithApi:self.appDelegate.api];
self.searchViewController = searchController;
_searchController.searchResultsTableView.delegate=self;
self.tableView.tableHeaderView = _searchController.searchBar;
}
Then it as enough to add this to allow variable heights:
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
id<TTTableViewDataSource> dataSource = (id<TTTableViewDataSource>)tableView.dataSource;
id object = [dataSource tableView:tableView objectForRowAtIndexPath:indexPath];
Class cls = [dataSource tableView:tableView cellClassForObject:object];
return [cls tableView:tableView rowHeightForObject:object];
}
And this to handle selection:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TTTableImageItemCell *cell = (TTTableImageItemCell *) [tableView cellForRowAtIndexPath:indexPath];
TTTableImageItem *object = [cell object];
[_delegate MessageAddRecipient:self didSelectObject:object];
}

Related

How to make SearchBar in tableview work?

So i am trying to make an application that displays names of people in a tableview and on tap moves to the next view controller that shows an image of the person.
However when i add the search bar on the table view; i dont seem to have it right.
What am i doing wrong here?
The code compiles and displays on the simulator but when i click on any of the buttons, it gives me the errors i hate the most (Thread 1 : signal SIGABRT)
Here is my code for the Table View Controller
#import "PhotoTableViewController.h"
#import "Photo.h"
#import "DisplayViewController.h"
#interface PhotoTableViewController ()
#end
#implementation PhotoTableViewController
#synthesize photoSearchBar, showPhotos, filteredPhotos;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
showPhotos = [NSArray arrayWithObjects:
[Photo photoofname:#"Main" filename:#"photo1.jpg" notes:#"Amazing Road Bike"],
[Photo photoofname:#"Back" filename:#"photo3.jpg" notes:#"this is the back"], nil];
[self.tableView reloadData];
self.filteredPhotos = [NSMutableArray arrayWithCapacity:[showPhotos count]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [filteredPhotos count];
} else {
return [showPhotos count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Photo *photo = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
photo = [filteredPhotos objectAtIndex:indexPath.row];
}else
{
photo = [showPhotos objectAtIndex:indexPath.row];
}
cell.textLabel.text = photo.name;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredPhotos removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchText];
filteredPhotos = [NSMutableArray arrayWithArray:[showPhotos filteredArrayUsingPredicate:predicate]];
}
#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark - TableView Delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Perform segue to candy detail
[self performSegueWithIdentifier:#"candyDetail" sender:tableView];
}
#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"photoDetail"]) {
UIViewController *candyDetailViewController = [segue destinationViewController];
// In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
if(sender == self.searchDisplayController.searchResultsTableView) {
NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
NSString *destinationTitle = [[filteredPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
else {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *destinationTitle = [[showPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
}
}
Also this is the code for my Objective C Class called Photo
#import "Photo.h"
#implementation Photo
#synthesize name,filename,notes;
+(id) photoofname: (NSString*)name filename:(NSString*)filename notes:(NSString*)notes{
Photo *newPhoto = [[Photo alloc]init];
newPhoto.name = name;
newPhoto.filename = filename;
newPhoto.notes = notes;
return newPhoto;
}
#end
Well, just by looking at the code what I can suggest you is, first remove that call to prepareForSegue method called in UITableView's delegate method, didSelectForRowAtIndexPath.
You are overriding prepareForSegue, so in your storyboard you should have a prototype cell from where you have to ctrl-drag to the destination controller and segue it accordingly. That's a basic concept. Still having problem? Let us see your console messages when it crashes.

CellForRowAtIndexPath is not invoked

I'm writing an app hat has many views and I used sliding views library (ECSlidingViews). The problem is when I fill an array with objects and fill the table with the objects in tableView:cellForRowIndexPath: method, it does present the data in the table, but when I go to other view and come back the data disappears because tableView:cellForRowIndexPath: is not called. Here is the code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"begin of cellForRowAtIndexPath");
SchedualeCell *cell = (SchedualeCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
Course *temp = [array objectAtIndex:indexPath.row];
cell.nameLb.text = temp.name;
cell.hourLb.text = [NSString stringWithFormat:#"%d",temp.hour];
cell.startTimeLb.text = temp.startTime;
cell.endTimeLb.text = temp.endTime;
NSLog(#"End of cellForRowAtIndexPath");
return cell;
}
tableView:numberOfRowsInSection: and numberOfSectionsInTableView: is invoked when I come back to the view that has the table view.
P.S.: The view is UIViewController that has table view inside of it, and I searched all StackOverflow before posting my problem.
EDIT : this is where I set the delegate and datasource
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Did Appear");
// Do any additional setup after loading the view.
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowRadius = 10.0f;
self.view.layer.shadowColor= [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]])
{
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
if (array == nil)
{
array = [[NSMutableArray alloc]init];
}
table.delegate = self;
table.dataSource = self;
[table reloadData];
}
and I did included The delegate and datasource in the header
#interface MainViewController : UIViewController<UITableViewDataSource , UITableViewDelegate,addDelegate>
First of all , it's not numberOfRowsAtSection and numberOfTableView. It's numberOfSectionsInTableView and numberOfRowsInSection.
Things you can do :
1) NSLog your numberOfRowsInSection. Note that , If it's "0" then your cellForRowAtIndexPath is never going to be called.
2) If you are using your UITableView inside some UIView then you should add :
[self.view addSubview:table];
3) Don't Forget to include :
#interface yourViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
Once check that you reframed the tableview in ViewWillAppear.
Some times if we set out of frame, CellForRowAtIndexPath will not call.

reload tableview after call to WCF service

I am calling a WCF service to display data in a UITableViewController.The code in the .m file is:
- (void)viewDidLoad
{
[super viewDidLoad];
[docTable setDataSource:self];
[docTable setDelegate:self];
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
EDViPadDocSyncService *service = [[EDViPadDocSyncService alloc]init];
EDVCategory *cat = [EDVCategory alloc];
cat.categoryId = [catId intValue];
[service getDocsByCatId:self action:#selector(getDocsByCatIdHandler:) category:cat];
[docTable reloadData];
}
- (void) getDocsByCatIdHandler: (id)value
{
if([value isKindOfClass:[NSError class]])
{
NSLog(#"%#", value);
return;
}
if([value isKindOfClass:[SoapFault class]])
{
NSLog(#"%#", value);
return;
}
NSMutableArray* result = (NSMutableArray*)value;
NSMutableArray *documentList = [[NSMutableArray alloc] init];
self.myDocList = [[NSMutableArray array] init];
for (int i = 0; i < [result count]; i++)
{
EDVDocument *docObj = [[EDVDocument alloc]init];
docObj = [result objectAtIndex:i];
[documentList addObject:[docObj docName]];
}
self.myDocList = documentList;
[docTable reloadData];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int cnt = [self.myDocList count];
NSLog(#"ABC=%#",cnt);
return [self.myDocList count];
//return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DocumentCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DocumentCell"];
if (cell == nil)
{
cell = [[[DocumentCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"DocumentCell"] autorelease];
}
NSLog(#"cell text=%#",[self.myDocList objectAtIndex:indexPath.row]);
cell.lblDocName.text = [self.myDocList objectAtIndex:indexPath.row];
return cell;
}
I am using storyboard.I have hooked the "docTable",set the datasource and the delegate for "docTable".The problem is,the service is called after the call to "numberOfRowsInSection".So,'return [self.myDocList count]' is 0.I have put [docTable reloadData] in viewWillAppear as well as in the service handler,that is,"getDocsByCatIdHandler".But it isn't getting reloaded,as expected.Is there anything else I can try? EDIT:- This a Master-Detail application.I have used the same code for loading data in the "MasterViewController" UITableViewController and it works.When the user selects a cell in this table,I need to populate data in the second tableview by calling the WCF service.The second tableview isn't displaying data.
Everything looks good which leads me to believe you are not getting the results from the webservice you are expecting.
One small thing first thats not your problem. If result is in fact an array and there is an object in it, you shouldnt need to alloc a new EDVDocument.
EDVDocument *docObj = [result objectAtIndex:i];
Can you log the (id)value parameter to see what we're working with?
NSLog(#"%#", value);
If value is not an array, the cast wont complain, it will just work by not working. However, if it is an array you may be finding trouble with assigning your property (granted I dont know how its declared) to a local array. You can use the following function to create a new array with the elements of your temporary array;
self.myDocList = [[NSArray alloc] initWithArray:documentList];
[docTable reloadData];
I hope this helps.
I was facing the same issue when i have a async webService call. I was using a private Library to call webservice so my control goes to the library and after the response comes a method in Appdelegate is set as handler. So what you need to do is before calling the Webservice save the state of tableview in a shared variable and after you have received response set it back to tableView and then call the reload method. Something like below:
SharedView.tblView = self.tableView;
[webservice Call];
After Response:
self.tableView = SharedView.tblView;
[self.tableView reloadData];
Hope This Helps.

How to change the style of a UITableViewController programmatically in Xcode

I'm trying to change the style of a UITableViewController to grouped. I know you can do this when creating a new table view, but I have a class that extends UITableViewController, so I don't need to make a new table view. Here's my code:
#import "DetailViewController.h"
#import "NSArray-NestedArrays.h"
#implementation DetailViewController
#synthesize steak, sectionNames, rowControllers, rowKeys, rowLabels;
- (void)viewDidLoad {
sectionNames = [[NSArray alloc] initWithObjects:[NSNull null], NSLocalizedString(#"General", #"General"), nil];
rowLabels = [[NSArray alloc] initWithObjects:
[NSArray arrayWithObjects:NSLocalizedString(#"Steak Name", #"Steak Name"), nil],
[NSArray arrayWithObjects:NSLocalizedString(#"Steak Wellness", #"Steak Wellness"), NSLocalizedString(#"Steak Type", #"Steak Type"), NSLocalizedString(#"Other", #"Other"), nil]
, nil];
rowKeys = [[NSArray alloc] initWithObjects:
[NSArray arrayWithObjects:#"steakName", nil],
[NSArray arrayWithObjects:#"steakWellness", #"steakType", #"other", nil]
, nil];
// TODO: Populate row controllers array
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sectionNames count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id theTitle = [sectionNames objectAtIndex:section];
if ([theTitle isKindOfClass:[NSNull class]]) {
return nil;
}
return theTitle;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [rowLabels countOfNestedArray:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"SteakCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];
}
NSString *rowKey = [rowKeys nestedObjectAtIndexPath:indexPath];
NSString *rowLabel = [rowLabels nestedObjectAtIndexPath:indexPath];
cell.detailTextLabel.text = rowKey;
cell.textLabel.text = rowLabel;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// TODO: Push editing controller onto the stack
}
#end
- (instancetype)init
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self) {
}
return self;
}
Not following? What do you mean by you don't have to "make a new table view"?? You still have to instantiate one.
Either you created one already and it has the style you want, or you have to instantiate a new one and set the property on it.
tableView.style is READONLY. So you can't change the style of an existing one. You are going to have to do something like:
[MyTableViewSubClass initWithFrame:aFrame style:UITableViewStyleGrouped];
You can not just change the style of an UITableView. So you only have 2 options:
Make another UITableView which is grouped
Use custom cells
Hope it helps
You would take care of this when you instantiated your view controller.
For example, to instantiate a normal UITableViewController you would do the following.
UITableViewController *tblCtr = [[UITableViewController alloc]initWithStyle:UITableViewStyleGrouped];
Therefore, if you have extended UITableViewController then your init code should take care of this.
MyCustomTableViewController *mctvc = [[MyCustomTableViewController alloc]initWithStyle:UITableViewStyleGrouped];
To achieve this you will need to implement this method in your .m file. Below is an example of what your header and implementation file should contain for instantiation.
Header
#interface MyCustomTableViewController : UITableViewController
{
-(id)initWithStyle:(UITableViewStyle)style;
}
Implementation
#implementation MyCustomTableViewController
-(id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if(self)
{
...
return self;
}
return nil;
}
#end
When you call [super initWithStyle:style] the code provided by apple will take care of building the tableview for you with the requested view style.
You can create a new tableview to overwrite UITableviewController's tableview like this:
UITableView *tableView = [[UITableView alloc] initWithFrame:self.tableView.frame style:UITableViewStyleGrouped];
self.tableView = tableView;
simply buddy to allocate set the frame and style of table ..example code write down.
[tableObject initWithFrame:CGRectMake(x,y,width,height) style:UITableViewStyleGrouped];

Pull To Refresh on iphone not working as expected

I have been using this: http://blog.leahculver.com/2010/12/iphone-pull-to-refresh.html to make the pull to refresh function in my app.
But I cant see the text "Pull down to refresh...", "Release to refresh..." and "Loading...".
All I've done is copy the files into my project, link against QuartzCore framework, and changed the .h file of my view controller so it is a subclass of PullRefreshTableViewController. Then I added the refresh method.
Is seems that the initWithStyle method in PullRefreshTableViewController never is executed.
But i should be, in my tableViewcellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Text";
return cell; }
The initWithStyle method from the PullRefreshTableViewController.m:
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self != nil) {
textPull = [[NSString alloc] initWithString:#"Pull down to refresh..."];
textRelease = [[NSString alloc] initWithString:#"Release to refresh..."];
textLoading = [[NSString alloc] initWithString:#"Loading..."];
NSLog(#"in");
}
NSLog(#"out");
return self; }
The logs are never printed in the console
I really cant see where the problem is ?
Had the same problem.
figured out that not initWithStyle is called instead initWithCoder is called....
so to solve your problem insert following code in your PullRefreshTableViewController.m
and it works like a charm
-(id)initWithCoder:(NSCoder *)aDecoder{
NSLog(#"initWithCoder");
self = [super initWithCoder:aDecoder];
if (self != nil) {
textPull = [[NSString alloc] initWithString:#"Pull down to refresh..."];
textRelease = [[NSString alloc] initWithString:#"Release to refresh..."];
textLoading = [[NSString alloc] initWithString:#"Loading..."];
}
return self;
}
best regards
If you're looking for where the text is defined, it is on Line 43 of the PullRefreshTableViewController.m
Hope this helps (if it does don't forget to vote my answer up)
M.
Try instantiating the PullRefreshTableViewController with:
PullRefreshTableViewController *tableViewController = [[PullRefreshTableViewController alloc] initWithStyle:UITableViewStylePlain];
Instantiating the UITableViewCell using initWithSyle won't have any affect on your UITableViewController subclass.
The alternative is to edit the PullRefreshTableViewController class to override - (id)init method in a similar manner as done with initWithStyle: