Get MKLocalSearch to only return places - ios

I have looked at the documentation and can't find a way to use MKLocalSearch to only return areas. For example I want the search to search world wide for cities, towns, villages & counties but not return any businesses or hotels etc. Is that possible?
Thanks
D

I think you can use predicate like this:
NSPredicate *noBusiness = [NSPredicate predicateWithFormat:#"business.uID == 0"];
NSMutableArray *itemsWithoutBusinesses = [response.mapItems mutableCopy];
[itemsWithoutBusinesses filterUsingPredicate:noBusiness];
Example local search code is also adding, which will solve your problem.
-(void)issueLocalSearchLookup:(NSString *)searchString {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.location.coordinate, 30000, 30000);
self.localSearchRequest = [[MKLocalSearchRequest alloc] init];
self.localSearchRequest.region = region;
self.localSearchRequest.naturalLanguageQuery = searchString;
self.localSearch = [[MKLocalSearch alloc] initWithRequest:self.localSearchRequest];
[self.localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if(error){
NSLog(#"LocalSearch failed with error: %#", error);
return;
} else {
for(MKMapItem *mapItem in response.mapItems){
[self.data addObject:mapItem];
}
[self.searchDisplayController.searchResultsTableView reloadData];
}
}];
}

based on your requirement change the key parameter for addressDictionary.
for(MKMapItem *mapItem in response.mapItems)
{
NSLog(#"%#",mapItem.placemark.addressDictionary[#"Street"]);
}

Related

Check if a contact number exists or not in contacts list using CNContacts in iOS

I'm implementing a logic to check whether a contact exists or not in the contacts list and based upon this result I'm inserting the contact. My progress so far:
__block NSString *strPhoneNumber = #"1093874652";
if ([CNContactStore class]) {
CNContactStore *addressBook = [[CNContactStore alloc] init];
NSArray *keysToFetch =#[CNContactPhoneNumbersKey];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSError *error = nil;
CNContactFetchRequest *fetchRequest =[[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch];
__block BOOL isExists = NO;
[addressBook enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSArray *phoneNumbers =[[contact.phoneNumbers valueForKey:#"value"] valueForKey:#"digits"];
if ([phoneNumbers containsObject:strPhoneNumber]) {
isExists = YES;
*stop = YES;
}
else
isExists = NO;
}];
dispatch_async(dispatch_get_main_queue(), ^{
if (isExists == NO) {
//This is the method for saving the contacts. I'm not implementing here.
[self saveContactWithName:#"John Doe" withContactEmail:#"johndoe#abc.com#" withContactPhone:str];
}
});
});
}
Now, the problem is after enumerating, the code under if (isExists == NO) fires several times and saving the contact multiple times.How do I stop it? My only need is if the contact exits then don't save it otherwise save it only one time. Any help will be appreciated.
replace the below part in your code,
NSArray *phoneNumbers = [[contact.phoneNumbers valueForKey:#"value"] valueForKey:#"digits"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self == [c] %#", strPhoneNumber];
NSArray *filtered = [phoneNumbers filteredArrayUsingPredicate:predicate];
if ([filtered count] > 0) {
isExists = YES;
*stop = YES;
}
else
isExists = NO;
}];

How to cancel a completion handler in iOS

I want to get an array of nearby locations using mapkit framework. So when the user types in a textfield I call the following function.
- (void)searchForLocations:(NSString *)string
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(search:) object:nil];
[self performSelectorInBackground:#selector(search:) withObject:string];
}
- (void)search :(NSString *)string
{
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
}
As you can see I want to cancel the previous search if a new input text is coming. But the previous search is not cancelled. How can i cancel the previous search?
Thanks in advance.
There is a cancel method on MKLocalSearch. Have you tried that one?
Edit: Ah, sorry, I was being stupid. You need to keep a reference to your old search in some way in order to cancel it. Put it in a property which you can clear (i.e. set to nil) when the search is finished. Whenever you call the search function, cancel the previous search function (no "if" needed, nil swallows all), then create a new one
#property (nonatiomic, strong) MKLocalSearch *previousSearch;
- (void)search :(NSString *)string
{
[self.previousSearch cancel];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
self.previousSearch = nil;
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
self.previousSearch = search;
}
The MKLocalSearch object has a cancel method that you can use to cancel a pending search. You can't simply cancel the selector as you are trying to do as that selector will complete very quickly, with the MKLocalSearch dispatched in the background.
You will need a property to store your search object, so that you can tell if it is still searching and cancel the search if required.
#property (strong,nonatomic) MKLocalSearch *localSearch;
- (void)search :(NSString *)string
{
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
if (self.localSearch!=nil) {
if (self.localSearch.searching) {
[self.localSearch cancel];
self.localSearch=nil;
}
}
self.localSearch = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
}
Well you can use NSBlockOperation.
Suppose the global variable that you have used for NSBlockOperation is blockOperation. Then :
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
blockOperation = NSBlockOperation(block: { () -> Void in
if (response.mapItems.count == 0) {
NSLog(#"No Matches");
} else {
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
})
}];
Then you can use this blockOperation to cancel wherever you want as follows:
blockOperation.cancel()

Location Services not returning close places

I'm using a code which I will post after this to return the closest places based on what the user types in a UITextField using a natural language query. I store all the places in an array and that pass that array to the next scene (a UITableViewController) in prepareForSegue. Than I use the array to load all the places. On the simulator, it shows all the default locations that Apple has which makes sense. But then, I test it out on a real iPhone and despite enabling location services for the app, I still get default locations. I tried again and again but I could not get actual results. It worked once a few weeks ago, but since then it has stopped. Any ideas? Here is the code:
- (void) performSearch {
NSLog(_searchLabel.text);
MKLocalSearchRequest *request =
[[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = _searchLabel.text;
_foundPlaces = [[NSMutableArray alloc] init];
_foundPlacesD = [[NSMutableArray alloc]init];
//NSLog(_place);
MKLocalSearch *search =
[[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else{
for (MKMapItem *item in response.mapItems)
{
NSString *n = item.name;
[_foundPlaces addObject:n];
NSLog(n);
MKDirectionsRequest *dr = [MKDirectionsRequest new];
MKMapItem *source = [MKMapItem mapItemForCurrentLocation];
[dr setSource:source];
[dr setDestination:item];
MKDirections *directions = [[MKDirections alloc]initWithRequest:dr];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *mresponse, NSError *error) {
if(mresponse.routes.count == 0){
NSLog(#"No routes");
}
else{
for(MKRoute *route in mresponse.routes){
CLLocationDistance d = route.distance/1000;
NSString *dText = [NSString stringWithFormat:#"%g kilometers", d];
[_foundPlacesD addObject:dText];
NSLog(dText);
}
}
}];
}
[self performSegueWithIdentifier:#"locationResults" sender:self];
}
}];
}
I believe I fixed it. The error was that the segue was being performed outside the completion, when it should be performed inside.

Adding mapview annotations within parse query returns null randomly

I am creating an iOS app using Parse database(asynchronously) to store information that will be used when populating a mapview. I have been trying to figure out what is wrong for a long time and have done plenty of research without any luck. I have, however, found the source of the issue.
In my code, I am querying the parse database in hopes of getting the information I want and then storing the information in a custom pointAnnotation class, which is of type MkPointAnnotation. Each item is stored in an array of pointAnnotations, and once all items in the database have been stored in the array, the annotations are added to MyMapView. --I have tried adding the annotations as they are created, which does not change anything.
The issue I have been having is that randomly, the query will iterate under the for(PFObject *vendor in Vendors) and reach an error, calling NSLog(#"%#", error.debugDescription); which shows (null) in the output log. The amount of objects that return null seems to change each time I run the application, and occasionally it will work as expected. After adding a do while(pointArray.count < query.countObjects), the function will iterate roughly 20-30 times and then will add the correct number of annotations, however, it is extremely inefficient.
Is this an inefficiency within Parse or is there a better way to achieve the expected results?
PFQuery *query = [PFQuery queryWithClassName:#"Vendors"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *vendors, NSError *error){
NSMutableArray *pointArray = [[NSMutableArray alloc] init];
if (!error) {
// The find succeeded.
// Do something with the found objects
do {
pointArray = [[NSMutableArray alloc] init];
for (PFObject *vendor in vendors) {
NSDate *lastUpdated = vendor.updatedAt;
NSDate *today = [NSDate date];
NSDate *newDate = [lastUpdated dateByAddingTimeInterval:86400];
if (today <= newDate) {
PFGeoPoint *point = vendor[#"Location"];
NSString *vendor_ID = vendor[#"Vendor_ID"];
NSMutableArray *FruitList = vendor[#"Fruits"];
NSMutableArray *VeggieList = vendor[#"Veggies"];
NSMutableArray *addressArray = vendor[#"Address"];
NSString *startHr = vendor[#"Start_Time"];
NSString *endHr = vendor[#"End_Time"];
Boolean more = false;
NSString *moreString = vendor[#"And_More"];
if ([moreString isEqual: #"true"]) {
more = true;
}
CLLocationCoordinate2D location;
location.latitude = point.latitude;
location.longitude = point.longitude;
pointAnnotation *newAnnotation = [[pointAnnotation alloc] init];
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"ENGLISH"]){
FindCartsLabel.text = #"Find Carts within:";
MilesTextField.text = #"Show All";
milesArray=[[NSArray alloc]initWithObjects:#"Show All", #"1 Mile", #"5 Miles", #"10 Miles", #"20 Miles", nil];
AddressBar.placeholder = ENGLISH_Address;
newAnnotation.title = #"Good. To. Go. Vendor";
newAnnotation.fruits = FruitList;
newAnnotation.veggies = VeggieList;
}else if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"SPANISH"]){
FindCartsLabel.text = #"Encuentra Carros Dentro:";
newAnnotation.title = #"Good. To. Go. Vendedor";
AddressBar.placeholder = SPANISH_Address;
NSMutableArray *spanishFruitList = [[NSMutableArray alloc]init];
for (NSString *current in FruitList) {
MilesTextField.text = #"Mostrar Todo";
milesArray=[[NSArray alloc]initWithObjects:#"Mostrar Todo", #"1 Milla", #"5 Millas", #"10 Millas", #"20 Millas", nil];
if ([current isEqual:#"Apples"]) {
[spanishFruitList addObject:SPANISH_Apples];
}
if ([current isEqual:#"Bananas"]) {
[spanishFruitList addObject:SPANISH_Bananas];
}
if ([current isEqual:#"Citrus"]) {
[spanishFruitList addObject:SPANISH_Citrus];
}
if ([current isEqual:#"Mangos"]) {
[spanishFruitList addObject:SPANISH_Mangos];
}
if ([current isEqual:#"Strawberries"]) {
[spanishFruitList addObject:SPANISH_Strawberries];
}
if ([current isEqual:#"And More"]) {
[spanishFruitList addObject:SPANISH_More];
}
}
NSMutableArray *spanishVeggieList = [[NSMutableArray alloc]init];
for (NSString *current in VeggieList) {
if ([current isEqual:#"Avocados"]) {
[spanishVeggieList addObject:SPANISH_Avocados];
}
if ([current isEqual:#"Broccoli"]) {
[spanishVeggieList addObject:SPANISH_Broccoli];
}
if ([current isEqual:#"Carrots"]) {
[spanishVeggieList addObject:SPANISH_Carrots];
}
if ([current isEqual:#"Squash"]) {
[spanishVeggieList addObject:SPANISH_Squash];
}
if ([current isEqual:#"Onions"]) {
[spanishVeggieList addObject:SPANISH_Onions];
}
if ([current isEqual:#"Tomatoes"]) {
[spanishVeggieList addObject:SPANISH_Tomatoes];
}
if ([current isEqual:#"And More"]) {
[spanishVeggieList addObject:SPANISH_More];
}
}
newAnnotation.fruits = spanishFruitList;
newAnnotation.veggies = spanishVeggieList;
}
newAnnotation.coordinate = location;
newAnnotation.vendorID = vendor_ID;
newAnnotation.startHour = startHr;
newAnnotation.endHour = endHr;
newAnnotation.loc = point;
newAnnotation.isCustomAddress = false;
//newAnnotation.subtitle = address;
__block NSString *address = [NSString stringWithFormat:#"%# %#, %#, %#, %#",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4]];
__block NSString *currAddress = [NSString stringWithFormat:#"%# %#\n"
"%#, %#, %#\n"
"%#\n",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4], addressArray[5]];
newAnnotation.subtitle = address;
newAnnotation.addressFormatted = currAddress;
static NSString *identifier = #"MyLocation";
MKPinAnnotationView *currentView = [[MKPinAnnotationView alloc] initWithAnnotation:newAnnotation reuseIdentifier:identifier];
[pointArray addObject:currentView];
} else {
//[self viewDidLoad];
NSLog(#"%#", error.debugDescription);
}
//} ];
}
} while (pointArray.count < query.countObjects);
}
if (pointArray.count == query.countObjects) {
for (MKPinAnnotationView *currentPoint in pointArray) {
[self.MyMapView addAnnotation:currentPoint.annotation];
}
}
}];
Thanks in advance for the help. I do not really understand why this code would not complete after only one iteration.
The NSLog(#"%#", error.debugDescription); doesn't look like it's in the right place. It's in an else block that is associated with the if (today <= newDate) which is inside a block of code that is only executed if error is null which is why it says null in the log (when what it really means is "today > newDate"). – Anna

UITableView with complex cells is slow and laggy

I've almost finished my app and everything seems to work but the main view.
It's an UIViewController with an embedded UITableView.
I'm using Parse as the backend, and I get an array of the objects I need in my viewDidLoad method.
Each cell contains some data that I'm fetching in the tableView:cellForRowAtIndexPath and I'm afraid that this is the reason why my table view is so laggy, but I don't know how to fetch the data I need for each object in my array without having the indexPath.row number.
I've already made each cell element "opaque" as suggested in other answers.
This is my code, any help would be greatly appreciated:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellHT";
CellHT *cell = (CellHT *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[CellHT alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// self.hH is an NSArray containing all the objects
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
cell.lblTitle.text = [self.hH[indexPath.row] objectForKey:#"title"];
cell.lblVenueName.text = [self.hH[indexPath.row] objectForKey:#"venueName"];
cell.lblDistance.text = NSLocalizedString(#"Distance from you", nil);
self.geo = [self.hH[indexPath.row] objectForKey:#"coordinates"];
// the formatters are initialized in the viewDidLoad: method
self.formatData = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
[self.formatterData setDateFormat:self.formatData];
self.formatOra = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[self.formatterOra setDateFormat:self.formatOra];
self.dal = NSLocalizedString(#"from", nil);
self.ore = NSLocalizedString(#"at", nil);
CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];
CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude longitude:self.userGeo.longitude];
CLLocationDistance distance = [user distanceFromLocation:venueLoc];
if ([[prefs objectForKey:#"unit"] isEqualToString:#"km"]) {
cell.lblDist.text = [NSString stringWithFormat:#"%.1f Km", distance /1000];
} else {
cell.lblDist.text = [NSString stringWithFormat:#"%.1f Miles", distance /1609];
}
// compare the object's starting date with the current date to set some images in the cell
NSComparisonResult startCompare = [[self.hH[indexPath.row] objectForKey:#"startDate"] compare: [NSDate date]];
if (startCompare == NSOrderedDescending) {
cell.quad.image = [UIImage imageNamed:#"no_HT"];
cell.lblStartTime.textColor = [UIColor redColor];
} else {
cell.quad.image = [UIImage imageNamed:#"yes_HT"];
cell.lblStartTime.textColor = [UIColor colorWithRed:104.0/255.0 green:166.0/255.0 blue:66.0/255.0 alpha:1.0];
}
NSString *dataInizio = [NSString stringWithFormat:#"%# %# %# %#", self.dal, [self.formatterData stringFromDate:[self.hH[indexPath.row] objectForKey:#"startDate"]], self.ore, [self.formatterOra stringFromDate:[self.hH[indexPath.row] objectForKey:#"endDate"]]];
cell.lblStartTime.text = dataInizio;
PFObject *cat = [self.hH[indexPath.row] objectForKey:#"catParent"];
NSString *languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([languageCode isEqualToString:#"it"]) {
cell.lblCategory.text = [cat objectForKey:#"nome_it"];
} else if ([languageCode isEqualToString:#"es"]) {
cell.lblCategory.text = [cat objectForKey:#"nome_es"];
} else {
cell.lblCategory.text = [cat objectForKey:#"nome_en"];
}
//getting the image data from the Parse PFFile
PFFile *theImage = [self.hH[indexPath.row] objectForKey:#"photo"];
[theImage getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
cell.cellImageView.image = [UIImage imageWithData:data];
}
}];
//getting the cell object's owner and his profile
PFUser *usr = [self.hH[indexPath.row] objectForKey:#"parent"];
PFQuery *prof = [PFQuery queryWithClassName:#"Profile"];
prof.cachePolicy = kPFCachePolicyCacheThenNetwork;
[prof whereKey:#"parent" equalTo:usr];
[prof getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
//getting the object's rating and the number of votes
PFQuery *rateQuery = [PFQuery queryWithClassName:#"Rating"];
[rateQuery whereKey:#"parent" equalTo:object];
[rateQuery getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
float vote = [[object objectForKey:#"rate"] floatValue];
float temp = ((vote * 2) + 0.5);
int tempvote = (int)temp;
float roundedVote = (float)tempvote / 2;
// drawing the stars number, depending on the rating obtained
UIImage *starsImage = [UIImage imageNamed:#"stars"];
UIGraphicsBeginImageContextWithOptions(cell.imgVoto.frame.size, NO, 0);
CGPoint starPoint = (CGPoint) {
.y = (cell.imgVoto.frame.size.height * (2 * roundedVote + 1)) - (starsImage.size.height)
};
[starsImage drawAtPoint:starPoint];
cell.imgVoto.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.lblVoto.text = [NSString stringWithFormat:#"(%d)", [[object objectForKey:#"voters"] intValue]];
}
}];
}
}];
return cell;
}
EDIT: this is the cell code:
+ (void)initialize {
if (self != [HH class]) {
return;
}
}
-(id)initWithCoder:(NSCoder *)aDecoder {
if ( !(self = [super initWithCoder:aDecoder]) ) return nil;
self.cellImageView.image = [UIImage imageNamed:#"icona_foto"];
self.cellImageView.contentMode = UIViewContentModeScaleToFill;
self.formatterData = [[NSDateFormatter alloc] init];
self.formatData = [[NSString alloc] init];
self.formatterOra = [[NSDateFormatter alloc] init];
self.formatOra = [[NSString alloc] init];
self.formatData = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
[self.formatterData setDateFormat:self.formatData];
self.formatOra = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[self.formatterOra setDateFormat:self.formatOra];
self.lblVoto.text = #"(0)";
return self;
}
SECOND EDIT: this is the code in the viewDidLoad method:
PFQuery *hours = [PFQuery queryWithClassName:#"HH"];
hours.cachePolicy = kPFCachePolicyCacheThenNetwork;
// here I'm making lots of query constraints that I'll not include
[hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objectsNumber = objects.count;
self.hH = [[NSArray alloc] initWithArray:objects];
}
}];
[self.tableView reloadData];
}
I would move as much of the logic out of cellForRowAtIndexPath: as you can, it needs to be very light-weight to get good scrolling performance. You're doing a lot of work on the main thread, and I would do a lot more of this work when you get your model objects back from Parse (if you could post viewDidLoad I can give you more specific help) and update the table view when these calls are done:
[UIImage imageWithData:data]
anything to do with NSDateFormatter
CLLocation's initWithLatitude:longitude:
creating the rating stars image
None of these depend on the state of the table view, so they can be effectively precomputed and cached in a model object. If you simply scroll up and down the table, you're doing allo f the same work over and over, killing your performance.
Updated for the questioner's newest code:
I won't include all of your functionality here but this should give you an idea:
// create a single shared formatter instead of one per object
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
NSDateFormatter *timeFormatter = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objectsNumber = objects.count;
for (SomeObject *modelObj in objects) {
// if you can add properties to your model object directly, do that
// otherwise write a category on the Parse object to add the ones you need
modelObj.dateString = [NSString stringWithFormat:#"%# %# %# %#", modelObj.dal, [self.dateFormatter stringFromDate:[modelObj objectForKey:#"startDate"]], modelObj.ore, [self.timeFormatter stringFromDate:[modelObj objectForKey:#"endDate"]]];
// create your locations, images, etc in here too
}
self.hH = [[NSArray alloc] initWithArray:objects];
}
}];]
Then in cellForRowAtIndexPath:, take the precomputed properties and simply assign them to the appropriate labels, image views, etc.
It would be even better to do most of this processing off the main thread via GCD, but that is most likely out of scope for this question. See Using GCD and Blocks Effectively for more information. Just remember do only interact with UIKit from the main thread!
have a try by removing
CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];
CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude long itude:self.userGeo.longitude];
CLLocationDistance distance = [user distanceFromLocation:venueLoc];
This was at first sight , then I see your all your code and I realize a lot of image are used
Because UITableView takes some time to layout cells.
Solution:
step1. Set section number and row number to 0.
step2. Reload tableView in viewDidAppear.
Then your view controller cloud response quickly and then show cells.

Resources