UISearchbar Parse API - ios

I have a well-functioning search bar. Only one thing that I want to improve is NSTimer. I don`t know why, but when I start typing, it search me results after some delay.It woks perfectly. But I get for every typed letter 1 API each. It mean that if I put into search bar for example Sudan. I get 5 API instead of 1. Could you someone help me?
Thanks
TableViewControllerTOP.h
#interface TableViewControllerTOP : UITableViewController<UISearchDisplayDelegate, UISearchBarDelegate,UIScrollViewDelegate,UITableViewDataSource, UITableViewDelegate>
{
NSTimer *myTimer;
}
#property (strong, nonatomic) IBOutlet UITableView *MainTable;
#property (nonatomic, strong) UISearchBar *searchBar;
#property (nonatomic, strong) UISearchDisplayController *searchController;
#property (nonatomic, strong) NSMutableArray *searchResults;
#property (nonatomic, retain) NSTimer *myTimer;
#property (nonatomic, assign) BOOL isAscending;
TableViewControllerTOP.m
#interface TableViewControllerTOP ()
#property (strong,nonatomic) NSMutableArray *itemss;
#end
#implementation TableViewControllerTOP
#synthesize myTimer;
#synthesize searchBar;
#synthesize searchController;
#synthesize searchResults;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.isAscending = YES;
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:#selector(pulltorefresh) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
PFQuery *query = [PFQuery queryWithClassName:#"Countries"];
query.cachePolicy = kPFCachePolicyIgnoreCache;
[query addDescendingOrder:#"createdAt"];
[query setLimit:10];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *items = [NSMutableArray array];
for (id obj in objects)
{
[items addObject:obj];
}
self.itemss = items;
NSLog(#"%#", objects);
NSLog(#"%lu", (unsigned long)[objects count]);
[_MainTable reloadData];
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
[self searchitems];
}
-(void)searchitems
{
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
self.tableView.tableHeaderView = self.searchBar;
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];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
[self.navigationController.navigationBar setBarTintColor:[UIColor lightGrayColor]];
}
-(void)filterResults:(NSString *)searchTerm {
myTimer = [NSTimer scheduledTimerWithTimeInterval:3.0
target:self
selector:#selector(queryask)
userInfo:_itemss
repeats:NO];
}
-(void)queryask{
PFQuery *queryCapitalizedString = [PFQuery queryWithClassName:#"Countries"];
[queryCapitalizedString whereKey:#"CountryTitle" containsString:[searchBar.text capitalizedString]];
PFQuery *queryLowerCaseString = [PFQuery queryWithClassName:#"Countries"];
[queryLowerCaseString whereKey:#"CountryTitle" containsString:[searchBar.text lowercaseString]];
PFQuery *querySearchBarString = [PFQuery queryWithClassName:#"Countries"];
[querySearchBarString whereKey:#"CountryTitle" containsString:searchBar.text];
PFQuery *finalQuery = [PFQuery orQueryWithSubqueries:[NSArray arrayWithObjects:queryCapitalizedString,queryLowerCaseString, querySearchBarString,nil]];
[finalQuery findObjectsInBackgroundWithTarget:self selector:#selector(callbackWithResult:error:)];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (void)callbackWithResult:(NSArray *)items error:(NSError *)error
{
if(!error) {
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:items];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.itemss.count;
} else {
return self.searchResults.count;
}
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
tableView.rowHeight = 70.0f;
}
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath
{
static NSString *uniqueIdentifier = #"MainCell";
CustomCell3 *cell = nil;
cell = (CustomCell3 *) [self.tableView dequeueReusableCellWithIdentifier:uniqueIdentifier];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MainCell" owner:nil options:nil];
for (id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[CustomCell3 class]])
{
cell = (CustomCell3 *)currentObject;
break;
}
}
}
if (tableView == self.tableView) {
cell.MainTitle.text = [[self.itemss objectAtIndex:indexPath.row] objectForKey:#"CountryTitle"];
cell.DescriptTitle.text = [[self.itemss objectAtIndex:indexPath.row] objectForKey:#"DescriptTitle"];
[cell.FlagTitle setImageWithURL:[NSURL URLWithString:[[self.itemss objectAtIndex:indexPath.row] objectForKey:#"ImaURL"]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
}
if(tableView == self.searchDisplayController.searchResultsTableView) {
PFObject *searchedUser = [self.searchResults objectAtIndex:indexPath.row];
NSString *content = [searchedUser objectForKey:#"CountryTitle"];
NSString *desco = [searchedUser objectForKey:#"DescriptTitle"];
cell.DescriptTitle.text = desco;
cell.MainTitle.text = content;
NSString *image = [searchedUser objectForKey:#"ImaURL"];
[cell.FlagTitle setImageWithURL:[NSURL URLWithString:image]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
}
return cell;
}
#end

For a way to delay the search, take a look at this SO question:
Delay UISearchbar parsing
A good idea could be to combine this with Logan's suggestion. A search should often not be performed until a minimum of characters have been entered, to avoid too broad searches (not much point performing a search for anything containing "s" in many cases, depending on what you are searching).

Perhaps instead of a timer, you could implement a search bar delegate to run a query after some custom logic, perhaps every 3 letters?
- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if ((searchBar.text.length % 3) == 0) {
[self queryAsk];
}
}
Note: This logic isn't the best, and you might want to explore various parameters for when to search, but I think the concept improves over the timer because it would be more based on input. I think it would give you more control.

Related

iOS Parse UISearchBar

I am new to iOS. I am making an app in which i am getting data from Parse back-end all are working fine.
I did UISearchbar and it works well. But when a search produces more than 6 results (main table have 6 rows, but I search for another Parse class) , this leads to an error.
2015-06-09 14:10:23.318 Aero store[3238:347073] Terminating app due to uncaught exception 'NSRangeException', reason: '
-[__NSArrayM objectAtIndex:]: index 6 beyond bounds [0 .. 5]'
This is my code:
#import "CategoryTable.h"
#import "GoodsTable.h"
#import "Parse/Parse.h"
#interface CategoryTable ()<UISearchDisplayDelegate, UISearchBarDelegate>
#property (nonatomic, strong) UISearchDisplayController *searchController;
#property (nonatomic, strong) NSMutableArray *searchResults;
#end
#implementation CategoryTable
#synthesize categoryId;
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.goodsSearchBar contentsController:self];
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.delegate = self;
[self.searchDisplayController.searchBar setBackgroundImage:[UIImage imageNamed:#"menu-background"]
forBarPosition:0
barMetrics:UIBarMetricsDefault];
CGPoint offset = CGPointMake(0, self.goodsSearchBar.frame.size.height);
self.tableView.contentOffset = offset;
self.searchResults = [NSMutableArray array];
self.navigationController.navigationBar.barStyle = UIStatusBarStyleLightContent;
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#" " style:UIBarButtonItemStylePlain target:nil action:nil];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"] != nil) {
//Город установлен - > категории
NSLog(#"Gorod - %#", [[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"]);
//[self performSegueWithIdentifier:#"showCategory" sender:self];
}
else
{
//Город не установлен -> выбор города
NSLog(#"Gorod - %#", [[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"]);
}
//Установка лого
UIView *headerView = [[UIView alloc] init];
headerView.frame = CGRectMake(0, 0, 151, 20);
UIImageView *logoImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo"]];
logoImage.frame = CGRectMake(0, 0, 151, 20);
logoImage.contentMode = UIViewContentModeScaleAspectFit;
[headerView addSubview:logoImage];
[self.navigationItem setTitleView:headerView];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.parseClassName = #"Category";
self.pullToRefreshEnabled = NO;
self.paginationEnabled = NO;
}
return self;
}
//Слово для поиска
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
searchString = [searchString lowercaseString];
[self filterResults:searchString];
return NO;
}
//Запрос для поиска
-(void)filterResults:(NSString *)searchTerm {
if (searchTerm.length > 1) {
[PFCloud callFunctionInBackground:#"find"
withParameters:#{#"goodsName": searchTerm, #"city":[[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"]}
block:^(NSArray *goodsList, NSError *error) {
if (!error) {
NSLog(#"Найдено: %#",goodsList);
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:goodsList];
dispatch_async(dispatch_get_main_queue(), ^{
[self.searchController.searchResultsTableView reloadData];
});
}
}];
}
}
//Получени списка категорий
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query whereKey:#"cityName" equalTo:[[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"]];
if (self.objects.count == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
[query orderByAscending:#"createdAt"];
return query;
}
//Количество ячеек для результата поиска
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return self.searchResults.count;
}
else {
return self.objects.count;
}
}
//Обрезка пустых ячеек
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *sectionFooterView = [[UIView alloc] initWithFrame:
CGRectMake(0, 0, tableView.frame.size.width, 1)];
sectionFooterView.backgroundColor = [UIColor clearColor];
return sectionFooterView;
}
//Отрисовка ячеек категорий
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *identifier = #"categoryCell";
PFTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
if (tableView == self.tableView) {
UILabel *titleLabel = (UILabel*) [cell viewWithTag:200];
titleLabel.text = [object objectForKey:#"title"];
PFFile *thumbnail = [object objectForKey:#"image"];
PFImageView *catImageView = (PFImageView*)[cell viewWithTag:100];
catImageView.image = [UIImage imageNamed:#"placeholder"];
catImageView.file = thumbnail;
[catImageView loadInBackground];
}
else if(tableView == self.searchDisplayController.searchResultsTableView) {
NSLog(#"test");
PFObject *searchedUser = [self.searchResults objectAtIndex:indexPath.row];
cell.textLabel.text = [[searchedUser objectForKey:#"name"] capitalizedString];
}
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showGoods"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
GoodsTable *goods= segue.destinationViewController;
PFObject *object = [self.objects objectAtIndex:indexPath.row];
categoryId = [object objectForKey:#"title"];
NSLog(#"Category Name = %#", categoryId);
goods.cityName = [[NSUserDefaults standardUserDefaults] objectForKey:#"cityName"];
goods.categoryId = categoryId;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Please help me! I can not solve the problem for several days. :'(
Try
dispatch_async(dispatch_get_main_queue(), ^{
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:goodsList];
[self.searchController.searchResultsTableView reloadData];
});
to ensure editing your datasource and reloading your tablew view are done in the same dispatch queue.

Issue Deleting Row from UITableView

I'm using Parse to populate a table view which works fine. I'm trying to delete a row from the table view but get this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI length]: unrecognized selector sent to instance 0x7fd3f0f20f60'
Here is the code:
#import "CompletedJobs.h"
#import <Parse/Parse.h>
#interface CompletedJobs ()
#property (nonatomic, strong) NSMutableArray *jobs;
#property (nonatomic, strong) NSMutableArray *objectIds;
#property (nonatomic, strong) UIActivityIndicatorView *loadingIndicator;
#property (nonatomic, strong) UIRefreshControl *refresh;
#end
#implementation CompletedJobs
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView setDataSource:self];
[self.tableView setDelegate:self];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
self.loadingIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(width / 2, height / 2, 37, 37)];
self.loadingIndicator.center = CGPointMake(width / 2, height / 2 - 37);
self.loadingIndicator.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin);
self.loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
self.loadingIndicator.hidesWhenStopped = YES;
[self.view addSubview:self.loadingIndicator];
[self.loadingIndicator startAnimating];
[self getJobs];
self.refresh = [[UIRefreshControl alloc]init];
self.refresh.tintColor = [UIColor blackColor];
[self.refresh addTarget:self action:#selector(refreshData) forControlEvents:UIControlEventValueChanged];
self.refreshControl = self.refresh;
}
- (void)viewDidAppear:(BOOL)animated {
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)getJobs {
self.jobs = [[NSMutableArray alloc]init];
self.objectIds = [[NSMutableArray alloc]init];
PFQuery *query = [PFQuery queryWithClassName:#"Completed"];
[query setLimit:1000];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (NSDictionary *objectDictionary in objects) {
[self.jobs addObject:objectDictionary];
for (int i = 0; i < self.jobs.count; i++) {
[self.objectIds addObject:[self.jobs valueForKeyPath:#"objectId"]];
}
}
dispatch_async(dispatch_get_main_queue(), ^ {
[self.tableView reloadData];
[self.loadingIndicator stopAnimating];
});
}
else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)refreshData {
[self getJobs];
[self.refresh endRefreshing];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return self.jobs.count;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString *objectId = [self.objectIds objectAtIndex:indexPath.row];
PFQuery *query = [PFQuery queryWithClassName:#"Completed"];
[query getObjectInBackgroundWithId:objectId block:^(PFObject *job, NSError *error) {
[job deleteInBackground];
}];
[self getJobs];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
NSDictionary *jobDictionary = [self.jobs objectAtIndex:[indexPath row]];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"UITableViewCell"];
}
if (cell) {
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor blackColor];
cell.textLabel.text = [jobDictionary objectForKey:#"job"];
NSString *completedBy = [jobDictionary objectForKey:#"completedBy"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateStyle = NSDateFormatterLongStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
NSString *completedDate = [formatter stringFromDate:[jobDictionary objectForKey:#"date"]];
NSString *detailString = [NSString stringWithFormat:#"Completed by: %# on %#", completedBy, completedDate];
cell.detailTextLabel.text = detailString;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
#end

Implementing PFQueryTableViewController with Cache

Had a little bit of trouble replacing my TableViewController with PFQueryTableViewController, but I got it working with pull to refresh and pagination. However, I can't get the cache to work (at the very bottom of the .m file). Any ideas on what's going on?
The only other change I made here was subclass the image in the cell as PFImage.
ContactsTableViewController.h
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import "FilterViewController.h"
#interface ContactsTableViewController : PFQueryTableViewController <UITableViewDelegate>
#property (nonatomic) NSString *titleName;
#property (nonatomic) NSString *date;
#property (nonatomic) NSString *price;
#property (nonatomic) NSString *imageName;
#property (nonatomic) NSString *venue;
#property (nonatomic) UIImage *image;
#property (nonatomic) NSString *filter;
#property (nonatomic) NSArray *eventsArray;
-(void)retrieveEvents;
-(void)filterEvents;
#end
ContactsTableViewController.m
#import "ContactsTableViewController.h"
#import "CustomCellTableViewCell.h"
#import "DetailViewController.h"
#interface ContactsTableViewController ()
#end
#implementation ContactsTableViewController
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
// The className to query on
self.parseClassName = #"eventsList";
// The key of the PFObject to display in the label of the default cell style
// self.textKey = #"name";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = NO;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(retrieveEvents)];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(filterEvents) name:#"updateParent" object:nil];
self.view.backgroundColor = [UIColor colorWithRed:245/255.0 green:243/255.0 blue:240/255.0 alpha:1];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.eventsArray count];
}
// Parse Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"cellID";
CustomCellTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
self.titleName = [tempDict objectForKey:#"eventTitle"];
self.price = [tempDict objectForKey:#"eventPrice"];
self.date = [tempDict objectForKey:#"eventDate"];
self.venue = [tempDict objectForKey:#"eventVenue"];
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
customCell.customImageView.image = [UIImage imageWithData:data];
}
}];
customCell.titleLabel.text = self.titleName;
customCell.priceLabel.text = self.price;
customCell.customDateLabel.text = self.date;
customCell.venueNameLabel.text = self.venue;
return customCell;
}
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor darkGrayColor]];
tableView.separatorColor = [UIColor clearColor];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showEventDetail"]) {
DetailViewController *destinationVC = [[DetailViewController alloc] init];
destinationVC = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
destinationVC.eventTitle = [tempDict objectForKey:#"eventTitle"];
destinationVC.eventPrice = [tempDict objectForKey:#"eventPrice"];
destinationVC.eventDate = [tempDict objectForKey:#"eventDate"];
destinationVC.venueName = [tempDict objectForKey:#"eventVenue"];
destinationVC.navigationItem.title = [tempDict objectForKey:#"eventTitle"];
// Image
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
destinationVC.eventImageView.image = [UIImage imageWithData:data];
destinationVC.eventImage = [UIImage imageWithData:data];
}
}];
// GeoPoint
destinationVC.geoPoint = [tempDict objectForKey:#"GeoPoint"];
} else if ([segue.identifier isEqualToString:#"showFilterTable"]){
FilterViewController *vc = (FilterViewController *)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
[vc setDelegate:self];
}
}
-(void)retrieveEvents
{
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
}
[self.tableView reloadData];
}];
}
-(void)filterEvents
{
if ([self.filter isEqualToString:#"All Events"]) {
[self performSelector:#selector(retrieveEvents)];
return;
}
NSLog(#"retrieveEvents: %#", self.filter);
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents whereKey:#"eventType" equalTo:self.filter];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
NSLog(#"%#", self.eventsArray);
}
[self.tableView reloadData];
}];
}
// Parse Method
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
return query;
}
#end
From the looks of it you are not using the queryForTable to populate the tableview, you are using your separate query.
This query never gets used in your tableview
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
return query;
}
Instead this one does:
-(void)retrieveEvents
{
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
}
[self.tableView reloadData];
}];
}
kPFCachePolicyCacheThenNetwork means to use both cache and network (first get from cache for quickness, then get from network for up-to-date-ness the next time). Try instead using kPFCachePolicyCacheElseNetwork.
Try this code. It may not be perfect. But I believe it should at least head you in the right direction.
#import "ContactsTableViewController.h"
#import "CustomCellTableViewCell.h"
#import "DetailViewController.h"
#interface ContactsTableViewController ()
#end
#implementation ContactsTableViewController
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
// The className to query on
self.parseClassName = #"eventsList";
// The key of the PFObject to display in the label of the default cell style
// self.textKey = #"name";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = NO;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(filterEvents) name:#"updateParent" object:nil];
self.view.backgroundColor = [UIColor colorWithRed:245/255.0 green:243/255.0 blue:240/255.0 alpha:1];
tableView.separatorColor = [UIColor clearColor];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//This reloaded the PFQueryTableView
[self loadObjects];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.objects.count;
}
// Parse Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"cellID";
CustomCellTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFObject *object = [self objectAtIndexPath:indexPath];
customCell.titleLabel.text = object[#"eventTitle"];
customCell.priceLabel.text = object[#"eventPrice"];
customCell.customDateLabel.text = object[#"eventDate"];
customCell.venueNameLabel.text = object[#"eventVenue"];
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
customCell.customImageView.image = [UIImage imageWithData:data];
}
}];
return customCell;
}
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor darkGrayColor]];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showEventDetail"]) {
DetailViewController *destinationVC = [[DetailViewController alloc] init];
destinationVC = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
destinationVC.eventTitle = [tempDict objectForKey:#"eventTitle"];
destinationVC.eventPrice = [tempDict objectForKey:#"eventPrice"];
destinationVC.eventDate = [tempDict objectForKey:#"eventDate"];
destinationVC.venueName = [tempDict objectForKey:#"eventVenue"];
destinationVC.navigationItem.title = [tempDict objectForKey:#"eventTitle"];
// Image
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
destinationVC.eventImageView.image = [UIImage imageWithData:data];
destinationVC.eventImage = [UIImage imageWithData:data];
}
}];
// GeoPoint
destinationVC.geoPoint = [tempDict objectForKey:#"GeoPoint"];
} else if ([segue.identifier isEqualToString:#"showFilterTable"]){
FilterViewController *vc = (FilterViewController *)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
[vc setDelegate:self];
}
}
// Parse Method
-(NSString *)filter
{
return _filter;
}
-(void)setFilter
{
_filter = filter;
[self loadObjects];
}
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
if (self.filter && ![self.filter isEqualToString:#"All Events"]) [query whereKey:#"eventTitle" equalTo:self.filter];
[query setLimit:300];
[query orderByAscending:#"eventTitle"];
return query;
}
#end

NSMutable Array problems

All,
I have an issue with my NSMutable array LogoURL. when the UITable reloads it only shows at array location [0] and not at [1] or [2]. Here is my code, can someone look at see where I am going wrong. Its very minor problem but its driving me crazy!
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) MSTable *table;
#property (nonatomic, strong) NSMutableArray *items;
#property (weak, nonatomic) IBOutlet UITableView *MainTableView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// create the activity indicator in the main queue
self.MainTableView.hidden = YES;
UIActivityIndicatorView *ac = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:ac];
[ac startAnimating];
self.client = [MSClient clientWithApplicationURLString:#"https://outnight-mobile.azure-mobile.net/" applicationKey:#"okYeRGfBagYrsbkaqWIRObeDtktjkF10"];
self.table = [self.client tableWithName:#"notifications"];
self.logoURL = [[NSMutableArray alloc] init];
self.rowitems = [[NSMutableArray alloc] init];
MSQuery *query = [self.table query];
query.fetchLimit = 3;
[query readWithCompletion:^(NSArray *items, NSInteger totalCount, NSError *error)
{
self.rowitems = [items mutableCopy];
//[self.MainTableView reloadData];
int a;
for (a = 0; a < 3; a++)
{
NSDictionary *apt = [self.rowitems objectAtIndex:a];
NSLog(#"%#", apt[#"barID"]);
NSDictionary *barIDDictionary = #{ #"myParam": apt[#"barID"]};
self.client = [MSClient clientWithApplicationURLString:#"https://outnight-mobile.azure-mobile.net/" applicationKey:#"okYeRGfBagYrsbkaqWIRObeDtktjkF10"];
[self.client invokeAPI:#"photos" body:barIDDictionary HTTPMethod:#"POST" parameters:nil headers:nil completion:^(id result, NSHTTPURLResponse *response, NSError *error) {
if (error) {
NSLog(#"Error %#", error );
}
else {
NSString *string = [NSString stringWithFormat:#"%#", [result objectForKey:#"rows"]];
NSString *stringWithoutbracketsend = [string stringByReplacingOccurrencesOfString:#")" withString:#""];
NSString *stringWithoutbracketsfront = [stringWithoutbracketsend stringByReplacingOccurrencesOfString:#"(" withString:#""];
NSString *completion = [stringWithoutbracketsfront stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *newStr = [completion substringFromIndex:1];
NSString *finalstring = [newStr substringToIndex:newStr.length-(newStr.length>0)];
[self.logoURL addObject:finalstring];
[self.MainTableView reloadData];
}
}];
}
}];
self.MainTableView.hidden = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.rowitems count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
NSDictionary *stress = [self.rowitems objectAtIndex:indexPath.row];
cell.textLabel.text = stress[#"content"];
switch (indexPath.row) {
case 0:
[cell.imageView setImageWithURL:[NSURL URLWithString:[self.logoURL objectAtIndex:(0)]] placeholderImage:[UIImage imageNamed:#"greybox40.png"]];
break;
case 1:
[cell.imageView setImageWithURL:[NSURL URLWithString:[self.logoURL objectAtIndex:(1)]] placeholderImage:[UIImage imageNamed:#"greybox40.png"]];
break;
case 2:
//[cell.imageView setImageWithURL:[NSURL URLWithString:[self.logoURL objectAtIndex:(2)]] placeholderImage:[UIImage imageNamed:#"greybox40.png"]];
break;
}
return cell;
}
#end
It is erroring at CASE (1), cos it cannot see the object. any help would be brilliant, thanks.
Error at case (1) happens because you reload your table view 3 times. and every time you say to your tableView that it has 3 rows via numberOfRowsInSection: method. But in first and second iteration your self.logoURL has only 1 and then 2 objects. try this code:
if (self.logoURL.count > indexPath.row) {
[cell.imageView setImageWithURL:[NSURL URLWithString:self.logoURL[indexPath.row]] placeholderImage:[UIImage imageNamed:#"greybox40.png"]];
}
else
cell.imageView.image = nil;
also, you dont need to create NSMutableArray instance self.rowitems = [[NSMutableArray alloc] init]; because you then reassign self.rowitems property self.rowitems = [items mutableCopy];
because your for loop is override the array value and store last value only.
[array insertObject:finalString atIndex:i];
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.logoURL count];
}

UISearchDisplayController displaying results parse

I have got fully working UISearchDisplayController implied in my UITableView made with Parse.com. Anyway when I put to search for, I always get only results starts with that letter. I want to display every data contains that letter.
For example: I put Om into my search and it searched me only : Oman and Ombudsman . I have in my UITableView also a cell named Community . You see this word also contains om but my search don`t display anything. It displays just words staring with these letters.
Can someone help me? Thank you.
#implementation TableViewController3
#synthesize MainTable;
#synthesize searchBar;
#synthesize searchController;
#synthesize searchResults;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetaill"]) {
{
DetailViewController3 *sdvc = (DetailViewController3 *)[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.objc = object;
} else {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
DetailViewController3 *detailViewController = [segue destinationViewController];
detailViewController.objc = object;
}
}
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
self.tableView.tableHeaderView = self.searchBar;
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];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
[self.navigationController.navigationBar setBarTintColor:[UIColor lightGrayColor]];
-(void)filterResults:(NSString *)searchTerm {
PFQuery *query = [PFQuery queryWithClassName: #"Countries"];
[query whereKey:#"CountryTitle" hasPrefix:searchTerm];
query.limit = 50;
[query findObjectsInBackgroundWithTarget:self selector:#selector(callbackWithResult:error:)];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (void)callbackWithResult:(NSArray *)celebrities error:(NSError *)error
{
if(!error) {
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:celebrities];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count;
}
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
tableView.rowHeight = 70.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
NSString *uniqueIdentifier = #"MainCell";
CustomCell3 *cell = nil;
cell = (CustomCell3 *) [self.tableView dequeueReusableCellWithIdentifier:uniqueIdentifier];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MainCell" owner:nil options:nil];
for (id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[CustomCell3 class]])
{
cell = (CustomCell3 *)currentObject;
break;
}
}
}
if (tableView == self.tableView) {
cell.MainTitle.text = [object objectForKey:#"CountryTitle"];
cell.DescriptTitle.text = [object objectForKey:#"DescriptTitle"];
[cell.FlagTitle setImageWithURL:[NSURL URLWithString:[object objectForKey:#"ImaURL"]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
}
if(tableView == self.searchDisplayController.searchResultsTableView) {
PFObject *searchedUser = [self.searchResults objectAtIndex:indexPath.row];
NSString *content = [searchedUser objectForKey:#"CountryTitle"];
NSString *desco = [searchedUser objectForKey:#"DescriptTitle"];
cell.DescriptTitle.text = desco;
cell.MainTitle.text = content;
NSString *image = [searchedUser objectForKey:#"ImaURL"];
[cell.FlagTitle setImageWithURL:[NSURL URLWithString:image]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"background.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:5.0] ];
}
return cell;
}
#end
Use - (void)whereKey:(NSString *)key containsString:(NSString *)substring instead of - (void)whereKey:(NSString *)key hasPrefix:(NSString *)prefix
-(void)filterResults:(NSString *)searchTerm {
PFQuery *query = [PFQuery queryWithClassName: #"Countries"];
[query whereKey:#"CountryTitle" containsString:searchTerm];
query.limit = 50;
[query findObjectsInBackgroundWithTarget:self selector:#selector(callbackWithResult:error:)];
}
if you use hasPrefix: then the search results will be elements starting with your search string.

Resources