Mutable Array sometimes working for images in UITableView - ios

I am getting a very strange array issue with LogoURL. Sometimes it works and sometimes it errors when trying to display the URL's in the array as an image. This is an Mutable array problem and 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://mobile.net/" applicationKey:#""];
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 insertObject:finalstring atIndex:a];
[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"];
if (self.logoURL.count > indexPath.row) {
[cell.imageView setImageWithURL:[NSURL URLWithString:self.logoURL[indexPath.row]] placeholderImage:[UIImage imageNamed:#"greybox40.png"]];
NSLog(#"%#", self.logoURL[indexPath.row]);
}
else
cell.imageView.image = nil;
return cell;
}
#end
I need some fresh eyes on it, can anyone advice ?
thanks

I don’t know much about MSQuery, but if the completion block can be in a separate thread, this is going to mess you up.
The tableView can call -tableView:numberOfRowsInSection: when you have some number of rows, and then call -tableView:cellForRowAtIndexPath: when there’s a totally different number.
Also I don’t know what MSClient is, but if it’s running its completion block in a background thread you’re reloading your tableView in a background thread, so that’s gonna kill you, too.

Related

NSSortDescriptor doesn't update UITableView

I'm trying to sort my tableview using NSSortDescriptor in a UISegmentedControl. When I log the Array to sort it shows the correct sorting order, but the tableview doesn't update after calling [self.tableView reloadData];
The data comes from an array which is populated by a json feed. I'm not using NSObjects to display the tableview, it's all populated from the NSArray. See code below:
#interface LinksTableViewController (){
NSArray *data;
}
#property (strong, nonatomic) NSArray *links;
#property (strong, nonatomic) NSArray *tNames;
#property (strong, nonatomic) NSArray *dThor;
#property (strong, nonatomic) NSArray *theLinker;
#property (strong, nonatomic) NSArray *anText;
#property (strong, nonatomic) NSArray *noDo;
#end
#implementation LinksTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
UISegmentedControl *statFilter = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"STAT1", #"STAT2", #"STAT3", #"STAT4", nil]];
[statFilter sizeToFit];
[statFilter addTarget:self action:#selector(MySegmentControlAction:) forControlEvents: UIControlEventValueChanged];
self.navigationItem.titleView = statFilter;
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(refreshdelay:) userInfo:nil repeats:NO];
}
- (void)MySegmentControlAction:(UISegmentedControl *)segment
{
NSArray *arrayToSort = data;
if (segment.selectedSegmentIndex == 0)
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"pda" ascending:NO];
arrayToSort = [arrayToSort sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"%#", arrayToSort);
}
else if (segment.selectedSegmentIndex == 1)
{
}
else if (segment.selectedSegmentIndex == 2)
{
}
else if (segment.selectedSegmentIndex == 3)
{
}
[self.tableView reloadData];
}
-(void)refreshdelay:(NSTimer*)timer
{
NSString *myString = [links absoluteString];
NSURL *JSONData = [NSURL URLWithString:myString];
NSData *datas = [NSData dataWithContentsOfURL:JSONData];
NSURLRequest *request = [NSURLRequest requestWithURL:JSONData];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.responseSerializer.acceptableContentTypes = [operation.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonResult = [NSJSONSerialization JSONObjectWithData:datas options:kNilOptions error:nil];
data = jsonResult;
NSMutableArray *names = [NSMutableArray array];
NSMutableArray *bLinks = [NSMutableArray array];
NSMutableArray *daThor = [NSMutableArray array];
NSMutableArray *bsLink = [NSMutableArray array];
NSMutableArray *ancTxt = [NSMutableArray array];
NSMutableArray *folLowd = [NSMutableArray array];
for (id itemfeed in jsonResult){
[names addObject:[NSString stringWithFormat:#"%#", itemfeed[#"ut"]]];
[bsLink addObject:[NSString stringWithFormat:#"%#", itemfeed[#"uu"]]];
[bLinks addObject:[NSString stringWithFormat:#"%#", itemfeed[#"upa"]]];
[daThor addObject:[NSString stringWithFormat:#"%#", itemfeed[#"pda"]]];
[ancTxt addObject:[NSString stringWithFormat:#"%#", itemfeed[#"lt"]]];
[folLowd addObject:[NSString stringWithFormat:#"%#", itemfeed[#"lf"]]];
self.links = names;
self.tNames = bLinks;
self.dThor = daThor;
self.theLinker = bsLink;
self.anText = ancTxt;
self.noDo = folLowd;
}
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
static NSString *Cellidentifier = #"DataTableCellId";
LICustomCell *cell = (LICustomCell *) [tableView dequeueReusableCellWithIdentifier:Cellidentifier];
if (cell == nil) {
cell = [[LICustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Cellidentifier];
NSArray *nib = [[NSBundle mainBundle]loadNibNamed:#"LiCellView" owner:self options:nil];
cell = nib[0];
NSString *sLink = self.links[indexPath.row];
NSString *aLink = self.tNames[indexPath.row];
NSString *aDa = self.dThor[indexPath.row];
NSString *theInk = self.theLinker[indexPath.row];
NSString *thAnk = self.anText[indexPath.row];
NSString *fLink = self.noDo[indexPath.row];
cell.ageLable.text = theInk;
}
return cell;
}
Looks like the data for your tableView is in 6 different arrays.
NSString *sLink = self.links[indexPath.row];
NSString *aLink = self.tNames[indexPath.row];
NSString *aDa = self.dThor[indexPath.row];
NSString *theInk = self.theLinker[indexPath.row];
NSString *thAnk = self.anText[indexPath.row];
NSString *fLink = self.noDo[indexPath.row];
Shouldn't you be sorting all of them? As your code stands now it's not clear how arrayToSort is connected to the data model of your tableView. You have NSArray *arrayToSort = data;, but it's not clear where data is initialized or where it's set (seems like you would want to set that in your JSON competition block). You also need to call [self.tableView reloadData]; at the end of MySegmentControlAction.
You can create a subclass of NSObject that has 6 NSString properties call it something like MyObject (but more descriptive). Then do something like:
for (id itemfeed in jsonResult){
MyObject *object = [[MyObject alloc]init];
object.sLink = [NSString stringWithFormat:#"%#", itemfeed[#"ut"]];
object.aLink = [NSString stringWithFormat:#"%#", itemfeed[#"uu"]];
...
[self.data addObject:object];
}
In the JSON competition block.
You then change cellForRowAtIndexPath to include something like
MyObject *object = [self.data objectAtIndex:indexPath.row]
cell.ageLable.text = object.theInk;
If you go this route you also need to update:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"pda" ascending:NO];
specifically #"pda" to whatever you name the property in your NSObject subclass. #"dThor" if you follow the naming I used.

Tableview is not showing cells in the time i posted

I have created a app that fetches information from a blog and shows it in the app. After i fetch the data it is supposed to be shown on the table view. It shows the things that i have posted but the things are in alphabetical order rather than the time i posted the thing.
Here is the code
#implementation EventsTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstLettersArray = [NSMutableArray array];
self.eventsDictionary = [NSMutableDictionary dictionary];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self searchForEvents];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self searchForEvents];
}
- (void)searchForEvents
{
[self.searchBar resignFirstResponder];
NSString *eventsSearchUrlString = [NSString stringWithFormat:#"https://www.googleapis.com/blogger/v3/blogs/1562818803553764290/posts?key=AIzaSyBTOxz-vPHgzIkw9k88hDKd99ILTaXTt0Y"];
NSURL *eventsSearchUrl = [NSURL URLWithString:eventsSearchUrlString];
NSURLRequest *eventsSearchUrlRequest = [NSURLRequest requestWithURL:eventsSearchUrl];
NSURLSession *sharedUrlSession = [NSURLSession sharedSession];
NSURLSessionDataTask *searchEventsTask =
[sharedUrlSession dataTaskWithRequest:eventsSearchUrlRequest completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
dispatch_async(dispatch_get_main_queue(),
^{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if(error)
{
UIAlertView *searchAlertView = [[UIAlertView alloc] initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[searchAlertView show];
}
else
{
NSString *resultString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Search results: %#", resultString);
NSError *jsonParseError = nil;
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParseError];
if(jsonParseError)
{
UIAlertView *jsonParseErrorAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:jsonParseError.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[jsonParseErrorAlert show];
}
else
{
for(NSString *key in jsonDictionary.keyEnumerator)
{
NSLog(#"First level key: %#", key);
}
[self.firstLettersArray removeAllObjects];
[self.eventsDictionary removeAllObjects];
NSArray *searchResultsArray = [jsonDictionary objectForKey:#"items"];
//NSLog(#"test%#",searchResultsArray);
for(NSDictionary *eventsInfoDictionary in searchResultsArray)
{
Events *event = [[Events alloc] init];
event.eventName = [eventsInfoDictionary objectForKey:#"title"];
event.eventDescription =[eventsInfoDictionary objectForKey:#"content"];
NSLog(#"Event Name : %#",event.eventName);
NSLog(#"Event Description : %#",event.eventDescription);
NSString *eventsFirstLetter = [event.eventName substringToIndex:1];
NSMutableArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:eventsFirstLetter];
if(!eventsWithFirstLetter)
{
eventsWithFirstLetter = [NSMutableArray array];
[self.firstLettersArray addObject:eventsFirstLetter];
}
[eventsWithFirstLetter addObject:event];
[self.eventsDictionary setObject:eventsWithFirstLetter forKey:eventsFirstLetter];
if ([event.eventDescription containsString:#"<br />"]) {
NSString* eventDescrip = event.eventDescription;
NSString* stringWithoutHTMLtags = [eventDescrip stringByReplacingOccurrencesOfString:#"<br />" withString:#""];
event.eventDescription = stringWithoutHTMLtags;
}
NSLog(#"Event Name : %#",event.eventName);
NSLog(#"Event Description : %#",event.eventDescription);
}
[self.firstLettersArray sortUsingSelector:#selector(compare:)];
[self.tableView reloadData];
}
}
});
}];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[searchEventsTask resume];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.firstLettersArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *firstLetter = [self.firstLettersArray objectAtIndex:section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
return eventsWithFirstLetter.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"eventTitleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *firstLetter = [self.firstLettersArray objectAtIndex:indexPath.section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
Events *event = [eventsWithFirstLetter objectAtIndex:indexPath.row];
cell.textLabel.text = event.eventName;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
NSLog(#"Row selected %#",cellText);*/
NSString *firstLetter = [self.firstLettersArray objectAtIndex:indexPath.section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
Events *event = [eventsWithFirstLetter objectAtIndex:indexPath.row];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
DescriptionViewController *descriptionViewController = (DescriptionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"descriptionController"];
descriptionViewController.eventNameDesc = event.eventDescription;
descriptionViewController.navigationItem.title = event.eventName;
[self.navigationController pushViewController:descriptionViewController animated:YES];
}
#end
You are trying to sort firstLettersArray which contain Events objects by using standard sort: function which doesn't know how to work with your custom objects.
You can use sortedArrayUsingComparator: function like this:
[firstLettersArray sortedArrayUsingComparator:^NSComparisonResult(Events *obj1, Events *obj2) {
// return object comparison result here
}];
Edit: Also you need to have NSDate property in Events class and feel it with event created time. I believe event created time should be contained in eventsInfoDictionary. Eventually you will be able to compare obj1 and obj2 using NSDate property.
i think this line not working
[self.firstLettersArray sortUsingSelector:#selector(compare:)];
use this line of code may help you....
sortedArray = [anArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];

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

UISearchbar Parse API

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.

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];
}

Resources