I'm trying to do a search function in my table view, to return objects from my Parse.com class.
I'm getting this error when I try to make a search in the UISearchBar:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier FeaturedTableViewCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
Here's how I'm doing it:
#interface DiscoverViewController () <UISearchBarDelegate, UISearchDisplayDelegate>
#property (nonatomic, retain) PFQuery *query;
#property (nonatomic, retain) PFObject *category;
#end
#implementation DailyDiscoverViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.delegate = self;
self.searchResults = [NSMutableArray array];
_categories = [[NSMutableArray alloc] initWithCapacity:100];
}
- (void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName:#"Projects"];
[query whereKeyExists:#"name"];
[query whereKey:#"name" containsString:searchTerm];
NSArray *results = [query findObjects];
[self.searchResults addObjectsFromArray:results];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)refresh {
PFQuery *query = [PFQuery queryWithClassName:#"Categories"];
[query orderByDescending:#"name"];
[query findObjectsInBackgroundWithBlock:^(NSArray *posts, NSError *error) {
if (!error) {
//NSLog(#"%#", posts);
} else {
}
[_categories setArray:posts];
[self.tableView reloadData];
[_loadingView stopAnimating];
[_refreshControl endRefreshing];
}];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
if (section == 0) {
return 1;
} else {
return self.categories.count;
}
} else {
return self.searchResults.count;
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return 320;
} else {
return 52;
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
_featuredObject = [_featured objectAtIndex:indexPath.row];
DiscoverFeaturedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DiscoverFeaturedTableViewCell" forIndexPath:indexPath];
[(PFFile*)_featuredObject[#"picture"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.image1.image = [UIImage imageWithData:data];
}];
return cell;
} else {
_category = [_categories objectAtIndex:indexPath.row];
DiscoverTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DiscoverTableViewCell" forIndexPath:indexPath];
cell.name.text = _category[#"name"];
if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) {
PFUser *obj2 = [self.searchResults objectAtIndex:indexPath.row];
PFQuery *query = [PFQuery queryWithClassName:#"Projects"];
PFObject *searchedUser = [query getObjectWithId:obj2.objectId];
NSString *first = [searchedUser objectForKey:#"name"];
cell.name.text = [first substringToIndex:1];
cell.name.text = first;
return cell;
}
return cell;
}
}
#end
I think you can look this stack over flow post : POST
K.
Ok,
Try it on viewDidLoad:
YourCustomCell *yourCustomCell = [UINib
nibWithNibName:#"YourCustomCell" bundle:nil]; [self.tableView
registerNib:cellNib forCellReuseIdentifier:#"cell"];
Note: Your custom cell must have a .xib of course.
You could try this, I remember running into this exact issue and this was one of the solutions I tried:
[self.tableView registerClass:[DiscoverTableViewCell class] forCellReuseIdentifier:#"DiscoverTableViewCell"];
However, I distinctly remember that this didn't work. It turned out I hadn't correctly connected the cells in the storyboard. Furthermore, make sure that the class of your storyboard cell has been changed to represent your cell's custom class.
Related
Explanation of what's taking place: The user has added a job as their favorite within another view. Now the user is in the Favorites tab and decides that they no longer want the job as one of their favorites anymore, so they swipe to delete the job. They tap the delete button and the errors below take place...the code works as is, but it also deletes every single job the user has saved as a favorite, instead of just deleting the one job.
My code also gives me an alert of:
Warning: A long-running operation is being executed on the main thread.
Break on warnBlockingOperationOnMainThread() to debug.
#import "JobDetailViewController.h"
#import "MyFavoritesTableViewController.h"
#import "Parse/Parse.h"
#import "Job.h"
#import "JobListViewController.h"
#interface MyFavoritesTableViewController ()
#property (nonatomic, strong) NSString *mainTitle;
#property (nonatomic, strong) NSString *subTitle;
#end
#interface MyFavoritesTableViewController ()
#end
#implementation MyFavoritesTableViewController
{}
#synthesize mainTitle;
#synthesize subTitle;
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if ([PFUser currentUser]) {
// Custom the table
// The className to query on
self.parseClassName = #"Jobs";
// The key of the PFObject to display in the label of the default cell style
self.textKey = #"Position";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = YES;
// The number of objects to show per page
self.objectsPerPage = 30;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)objectsWillLoad {
[super objectsWillLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object: (PFObject *)object
{
static NSString *myJobsTableIdentifier = #"myFavsCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:myJobsTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myJobsTableIdentifier];
}
// Configure the cell
PFFile *thumbnail = [object objectForKey:#"imageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:#"AppIcon.png"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];
UILabel *positionLabel = (UILabel*) [cell viewWithTag:101];
positionLabel.text = [object objectForKey:#"Position"];
UILabel *rotationLabel = (UILabel*) [cell viewWithTag:102];
rotationLabel.text = [object objectForKey:#"Rotation"];
UILabel *locationLabel = (UILabel*) [cell viewWithTag:103];
locationLabel.text = [object objectForKey:#"Location"];
UILabel *typeLabel = (UILabel*) [cell viewWithTag:104];
typeLabel.text = [object objectForKey:#"Type"];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetailedView"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Job *job = [[Job alloc] init];
JobDetailViewController *destViewController = segue.destinationViewController;
PFObject *object = [self.objects objectAtIndex:indexPath.row];
job.position = [object objectForKey:#"Position"];
job.poc = [object objectForKey:#"POC"];
job.email = [object objectForKey:#"Email"];
job.phone = [object objectForKey:#"Phone"];
job.apply = [object objectForKey:#"Apply"];
job.imageFile = [object objectForKey:#"imageFile"];
job.rotation = [object objectForKey:#"Rotation"];
job.location = [object objectForKey:#"Location"];
job.type = [object objectForKey:#"Type"];
job.clearance = [object objectForKey:#"Clearance"];
job.job_description = [object objectForKey:#"Job_Description"];
job.qualifications = [object objectForKey:#"Qualifications"];
job.originalJob = object;
destViewController.job = job;
}
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([self.objects count] == indexPath.row) {
[self loadNextPage];
} else {
PFObject *photo = [self.objects objectAtIndex:indexPath.row];
NSLog(#"%#", photo);
// Do something you want after selected the cell
}
}
- (PFQuery *)queryForTable
{
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
PFQuery *myquery = [relation query];
if (self.pullToRefreshEnabled) {
myquery.cachePolicy = kPFCachePolicyNetworkOnly;
}
return myquery;
}
#pragma mark - DeleteJobViewDelegate
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
PFQuery *myquery = [relation query];
NSArray *array = [myquery findObjects];
for (PFObject *object in array)
{
[relation removeObject:object];
}
[user saveInBackground];
[self.tableView reloadData];
[self loadObjects];
}
#end
The problem is that you are removing all the objects from the Relation:
NSArray *array = [myquery findObjects];
for (PFObject *object in array)
{
[relation removeObject:object];
}
What your code is doing is going though your array and removing each object from the relation.
What you want to do is to delete the job for that cell only. You can get that using the indexPath:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"Favorites"];
[relation removeObject:[self.objects objectAtIndex:indexPath.row]];
[user saveInBackground];
[self.tableView reloadData];
[self loadObjects];
}
Your second problem:
Warning: A long-running operation is being executed on the main thread. Break on warnBlockingOperationOnMainThread() to debug.
That warning is because findObjects is a synchronous call. You should use the findObjectsInBackground instead. But if you make the changes I gave above, you won't need it.
I have a problem with my TableViewController. There is a custom cell, with a class, and various infos dynamically loaded. My TableViewController appears, but my cell doesn't display, but i can touch this, and my transition with infos are good.
Thanks for your answers.
TableViewController.m
#interface Chat() {
NSMutableArray *messages;
UIRefreshControl *refreshControl;
}
#property (strong, nonatomic) IBOutlet UITableView *tableMessages;
#end
#implementation Chat
NSString *cellIdentifier = #"ChatCell";
- (void)viewDidLoad {
[super viewDidLoad];
[_tableMessages registerClass:[ChatCell class] forCellReuseIdentifier:cellIdentifier];
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(loadMessages) forControlEvents:UIControlEventValueChanged];
[_tableMessages addSubview:refreshControl];
messages = [[NSMutableArray alloc] init];
[self loadMessages];
}
- (void)loadMessages {
if ([PFUser currentUser] != nil)
{
PFQuery *query = [PFQuery queryWithClassName:PF_MESSAGES_CLASS_NAME];
[query whereKey:PF_MESSAGES_USER equalTo:[PFUser currentUser]];
[query includeKey:PF_MESSAGES_LASTUSER];
[query orderByDescending:PF_MESSAGES_UPDATEDACTION];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error == nil) {
[messages removeAllObjects];
[messages addObjectsFromArray:objects];
[_tableMessages reloadData];
} else [ProgressHUD showError:#"Network error."];
[refreshControl endRefreshing];
}];
}
}
- (void)actionCleanup {
[messages removeAllObjects];
[_tableMessages reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[cell bindData:messages[indexPath.row]];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
DeleteMessageItem(messages[indexPath.row]);
[messages removeObjectAtIndex:indexPath.row];
[_tableMessages deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
PFObject *message = messages[indexPath.row];
ChatView *chatView = [[ChatView alloc] initWith:message[PF_MESSAGES_ROOMID]];
[self.navigationController pushViewController:chatView animated:YES];
}
#end
TableViewCell.m
#interface ChatCell() {
PFObject *message;
}
#end
#implementation ChatCell
- (void)bindData:(PFObject *)message_ {
message = message_;
_chatImg.layer.cornerRadius = _chatImg.frame.size.width/2;
_chatImg.layer.masksToBounds = YES;
PFUser *lastUser = message[PF_MESSAGES_LASTUSER];
[_chatImg setFile:lastUser[PF_USER_PICTURE]];
[_chatImg loadInBackground];
_chatUsername.text = message[PF_MESSAGES_DESCRIPTION];
_chatMessage.text = message[PF_MESSAGES_LASTMESSAGE];
NSTimeInterval seconds = [[NSDate date] timeIntervalSinceDate:message.updatedAt];
_chatDate.text = TimeElapsed(seconds);
}
#end
It's because you register the cell using - registerClass:forCellReuseIdentifier:.
If you register it this way you have to construct the view programmatically or load the nib file in ChatCell code.
To solve the problem, do either of these:
Create a nib file containing the view for your table view cell and set the class to ChatCell. Then use - registerNib:forCellReuseIdentifier: to register the nib.
Construct the view programmatically eg. create a UILabel and add it as a subview of ChatCell.
Make the prototype cell in the storyboard and set the cell identifier to ChatCell. Then remove the - registerClass:forCellReuseIdentifier:
Check You are given correct cell Identifier in storyboard. (case sensitive) " ChatCell"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ChatCell";
ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[cell bindData:messages[indexPath.row]];
return cell;
}
You are updating the UI on background thread. Try this, in your "loadMessages" method.
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
if (error == nil) {
[messages removeAllObjects];
[messages addObjectsFromArray:objects];
[_tableMessages reloadData];
} else [ProgressHUD showError:#"Network error."];
[refreshControl endRefreshing];
});
}];
When I run the application, the header view container space is there, and is visible. I'm trying to display the username inside the header view, but nothing is showing up. Here is my code so far in the tableView:
#import "HomeView.h"
#interface HomeView () <UIActionSheetDelegate, UIImagePickerControllerDelegate>
#end
#implementation HomeView
- (void)viewDidLoad {
[super viewDidLoad];
if ([PFUser currentUser]) {
NSLog(#"Welcome to the App, %#", [self.user objectForKey:#"username"]);
} else {
LoginView *loginView = [[LoginView alloc] init];
[loginView setHidesBottomBarWhenPushed:YES];
[loginView.navigationItem setHidesBackButton:YES];
[self.navigationController pushViewController:loginView animated:NO];
}
UIBarButtonItem *takePhoto = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:#selector(takePhoto:)];
self.navigationItem.rightBarButtonItem = takePhoto;
// [self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:#"cellIdentifier"];
// [self.tableView registerNib:[UINib nibWithNibName:#"HomeViewCell" bundle:nil]
// forCellReuseIdentifier:#"cellIdentifier"];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
self.reusableSectionHeaderViews = [NSMutableSet setWithCapacity:3];
}
return self;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
PFQuery *query = [PFQuery queryWithClassName:#"UserPhotos"];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
} else {
self.userPhotos = objects;
NSLog(#"Retrieved objects: %#", self.userPhotos);
[self.tableView reloadData];
}
}];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger sections = self.userPhotos.count;
// Return the number of sections.
return sections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 1;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == self.userPhotos.count) {
// Load More section
return nil;
}
HomeHeaderView *headerView = [self dequeueReusableSectionHeaderView];
if (!headerView) {
headerView = [[HomeHeaderView alloc] initWithFrame:CGRectMake( 0.0f, 0.0f, self.view.bounds.size.width, 44.0f) buttons:HomePhotoHeaderButtonsDefault];
headerView.delegate = self;
[self.reusableSectionHeaderViews addObject:headerView];
}
//Setting the username display.
PFObject *owner = [self.userPhotos objectAtIndex:section];
PFUser *user = [owner objectForKey:#"user"];
[user fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
NSString *username = user.username;
[headerView.userButton setTitle:username forState:UIControlStateNormal];
}
}];
return headerView;
}
- (HomeHeaderView *)dequeueReusableSectionHeaderView {
for (HomeHeaderView *sectionHeaderView in self.reusableSectionHeaderViews) {
if (!sectionHeaderView.superview) {
// we found a section header that is no longer visible
return sectionHeaderView;
}
}
return nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"cellIdentifier";
HomeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[HomeViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Setting the image in the cell.
PFObject *carPhoto = [self.userPhotos objectAtIndex:indexPath.row];
PFFile *imageFile = [carPhoto objectForKey:#"imageFile"];
NSURL *imageFileUrl = [[NSURL alloc] initWithString:imageFile.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
cell.carImage.contentMode = UIViewContentModeScaleAspectFit;
cell.carImage.image = [UIImage imageWithData:imageData];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 269;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == self.userPhotos.count) {
return 0.0f;
}
return 44.0f;
}
[user fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
NSString *username = user.username;
[headerView.userButton setTitle:username forState:UIControlStateNormal];
}
}];
The code above, you are updating the headerview UI from a background thread. You need to wrap the UI part so it performs on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[headerView.userButton setTitle:username forState:UIControlStateNormal];
};
You need to be careful though, you are performing a background operation and then updating the header which you are reusing. There is a chance that the header is reused for a new section before the operation finishes and it is then set with the wrong username for that section. You can take care of this by not reusing the header or canceling the network operation if the header scrolls off screen before the operation finishes.
in my app I'm using Parse.com as the holder of the data on a database and SearchBarDisplayController for research. I have prepared a following to prepare for my table in order to send the data cells in another view controller and works perfectly ... Now I am having a problem ...
How can I create a "prepareforsegue" for the SearchDisplayController, to activate the cells of the search results?
In here you can see the code for "Prepare for Segue" (or another Method) that I made and the data to be passed ...
Some Ideas on this? Thanks so much!
#import "Ricerca.h"
#import "Custom.h"
#import "DettagliProfilo.h"
#interface Ricerca () <UISearchDisplayDelegate, UISearchBarDelegate>
#property (nonatomic, strong) NSMutableArray *searchResults;
#end
#implementation Ricerca
#synthesize searchResults;
- (void)viewDidLoad {
[super viewDidLoad];
[self loadObjects];
self.searchResults = [NSMutableArray array];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// The className to query on
self.parseClassName = #"_User";
self.pullToRefreshEnabled = YES;
self.paginationEnabled = YES;
self.objectsPerPage = 10;
}
return self;
}
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
//[query whereKeyExists:#"username"];
//[query whereKeyExists:#"email"];
[query orderByAscending:#"username"];
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
return query;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait || UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
UITableViewCell *cell = (UITableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
// Configure the cell
UIColor *color = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.0];
cell.detailTextLabel.backgroundColor = color;
cell.textLabel.backgroundColor = color;
if (tableView == self.tableView) {
cell.textLabel.text = [object objectForKey:#"username"];
cell.detailTextLabel.text = [object objectForKey:#"email"];
cell.imageView.image = [UIImage imageNamed:#"unknown"];
PFFile *imageFile = [object objectForKey:#"foto"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.imageView.image =[UIImage imageWithData:data];
}];
}
else if(tableView == self.searchDisplayController.searchResultsTableView) {
PFObject *searchedUser = [self.searchResults objectAtIndex:indexPath.row];
NSString *content = [searchedUser objectForKey:#"username"];
NSString *email = [searchedUser objectForKey:#"email"];
cell.detailTextLabel.text = email;
cell.textLabel.text = content;
cell.imageView.image = [UIImage imageNamed:#"unknown"];
PFFile *imageFile = [searchedUser objectForKey:#"foto"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.imageView.image =[UIImage imageWithData:data];
}];
NSLog(#"Content: %#", content);
}
return cell;
}
- (void)callbackLoadObjectsFromParse:(NSArray *)result error:(NSError *)error {
if (!error) {
[self.searchResults removeAllObjects];
NSLog(#"Successfully fetched %d entries", result.count);
[self.searchResults addObjectsFromArray:result];
[self.searchDisplayController.searchResultsTableView reloadData];
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}
-(void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFUser query];
[query orderByAscending:#"username"];
[query whereKeyExists:#"email"];
[query whereKey:#"username" containsString:searchTerm];
query.cachePolicy = kPFCachePolicyNetworkOnly;
[query findObjectsInBackgroundWithTarget:self selector:#selector(callbackLoadObjectsFromParse:error:)];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
tableView.rowHeight = 80.0f; // or some other height
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
} else {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Check that a new transition has been requested to the DetailViewController and prepares for it
/*if ([segue.identifier isEqualToString:#"Dettaglio"]){
// Capture the object (e.g. exam) the user has selected from the list
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
DettagliProfilo *detailViewController = [segue destinationViewController];
detailViewController.Dettaglio = object;*/
if ([[segue identifier]isEqualToString:#"Dettaglio"])
{
DettagliProfilo *sdvc = (DettagliProfilo *)[segue destinationViewController];
if(self.searchDisplayController.active) {
NSIndexPath *indexPath = [[self tableView] indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
object = (PFObject *)[[self searchResults]objectAtIndex:[[[[self searchDisplayController]searchResultsTableView]indexPathForSelectedRow]row]];
sdvc.Dettaglio = object;
} else {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
DettagliProfilo *detailViewController = [segue destinationViewController];
detailViewController.Dettaglio = object;
}
}
}
#end
Hey together I am using Parse SDK for my App - the interface is build in Storyboard...
I am having a table view which get's his data from Parse, now I want to make it searchable.
I found this post and followed it but not came to a running result! :/
The search results are load but I having problems to display them...
I get the following errors:
... myApp[..] *** Assertion failure in -[UISearchResultsTableView _configureCellForDisplay:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:5471
... myApp[...] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
I tried a lot around but don't come to a result, here is my code - can anybody help:
Sorry for my bad english! ;)
#import "FirstLaunchViewController.h"
#interface FirstLaunchViewController ()
#end
#implementation FirstLaunchViewController
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadObjects];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"navbar_background.png"] forBarMetrics:UIBarMetricsDefault];
self.searchResults = [NSMutableArray array];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithClassName:#"teams"];
self = [super initWithCoder:aDecoder];
if (self) {
// The className to query on
self.parseClassName = #"teams";
self.textKey = #"verein";
// The key of the PFObject to display in the label of the default cell style
// self.keyToDisplay = #"text";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = NO;
// Whether the built-in pagination is enabled
self.paginationEnabled = YES;
self.loadingViewEnabled = NO;
// The number of objects to show per page
self.objectsPerPage = 50;
}
return self;
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait || UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
// Configure the cell
UIColor *color = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.0];
cell.detailTextLabel.backgroundColor = color;
cell.textLabel.backgroundColor = color;
cell.backgroundView = [ [UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"cellbackground_n.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0]];
cell.selectedBackgroundView = [ [UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"cellbackground_down_n.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0]];
cell.accessoryView = [[ UIImageView alloc ] initWithImage:[UIImage imageNamed:#"cellarrows.png" ]];
if (tableView == self.tableView) {
cell.textLabel.text = [object objectForKey:#"verein"];
} else {
PFUser *obj2 = [self.searchResults objectAtIndex:indexPath.row];
PFQuery *query = [PFQuery queryWithClassName:#"teams"];
PFObject *searchedUser = [query getObjectWithId:obj2.objectId];
NSString *content = [searchedUser objectForKey:#"verein"];
cell.textLabel.text = content;
NSLog(#"Content: %#", content);
}
return cell;
}
-(void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName: self.parseClassName];
[query whereKeyExists:#"verein"]; //this is based on whatever query you are trying to accomplish
[query whereKey:#"verein" containsString:searchTerm];
NSArray *results = [query findObjects];
NSLog(#"%#", results);
NSLog(#"%u", results.count);
[self.searchResults addObjectsFromArray:results];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count;
}
}
#end
The issue is that your tableView initially has no reusable cells to dequeue. You need to check whether the cell returned by dequeueReusableCellWithIdentifier: is nil, and create a cell if it is.
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (!cell)
{
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
// Configure the cell
...
This way, you are guaranteeing that cell has a value, so you can avoid returning nil from this method.
To handle tableView:didSelectRowAtIndexPath: correctly, you'll need to first check which tableView triggered the event, and handle it accordingly. Below is an example of how this could work - you'd need to substitute your own detail view controller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.tableView) {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
else {
PFUser *user = PFUser *obj2 = [self.searchResults objectAtIndex:indexPath.row];
MyDetailViewController *detailController = [[MyDetailViewController alloc] initWithObject:user];
[self.navigationController pushViewController:datailController animated:YES];
}
}