I have a problem when displaying a route in MapView if route has waypoints. I use DIRECTIONS GOOGLE API:
https://developers.google.com/maps/documentation/directions/
The route is not drawn using the road.
Any help? Thanks!!
The trouble images:
The code:
reponse = [self getRouteFromGoogleApiWithPoints:arrayOfCoords andMode:#"driving" error:error];
if(reponse == nil)
{
UIAlertView *succes= [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"txtError", nil) message:NSLocalizedString(#"ServerError", nil) delegate: self cancelButtonTitle: #"OK" otherButtonTitles: nil];
[succes show];
}
else
{
NSArray *routes = [reponse objectForKey:#"routes"];
NSDictionary *route = [routes objectAtIndex:0];
NSDictionary *polylineOverview = [route objectForKey:#"overview_polyline"];
NSString *polylinePoints = [polylineOverview objectForKey:#"points"];
NSArray *decodedPolyline = [self decodePolyLine:polylinePoints];
CLLocationCoordinate2D coords[[decodedPolyline count]];
int i=0;
for(CLLocation* loc in decodedPolyline)
{
CLLocationCoordinate2D c;
c.latitude = loc.coordinate.latitude;
c.longitude = loc.coordinate.longitude;
coords[i]=c;
i++;
}
MKPolyline *line = [MKPolyline polylineWithCoordinates:(CLLocationCoordinate2D*)coords count:decodedPolyline.count];
[mapview addOverlay:line];
[mapview setNeedsDisplay];
}
}
}
+ (NSMutableArray *)decodePolyLine: (NSString *)encoded {
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
+(NSDictionary*)getRouteFromGoogleApiWithPoints:(NSArray*)arrayOfPoints andMode:(NSString*)mode error:(NSError **)error
{
NSDictionary *result = nil;
NSString *waypoints = #"";
CLLocation* origin = [arrayOfPoints objectAtIndex:0];
CLLocation* destination = [arrayOfPoints objectAtIndex:arrayOfPoints.count - 1];
// Create the waypoints
for(int i = 1; i < arrayOfPoints.count - 2; i++)
{
CLLocation* current = [arrayOfPoints objectAtIndex:i];
waypoints = [waypoints stringByAppendingString:[NSString stringWithFormat:#"%f,%f%%7C",current.coordinate.latitude,current.coordinate.longitude]];
}
CLLocation* lastWaypoint = [arrayOfPoints objectAtIndex:arrayOfPoints.count - 2];
waypoints = [waypoints stringByAppendingString:[NSString stringWithFormat:#"%f,%f",lastWaypoint.coordinate.latitude,lastWaypoint.coordinate.longitude]];
NSString *urlString =[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&waypoints=%#&sensor=true&mode=%#",origin.coordinate.latitude,origin.coordinate.longitude,destination.coordinate.latitude,destination.coordinate.longitude,waypoints,mode];
NSDictionary* response = [self getDictionaryFromURLString:urlString withParameters:nil error:error];
if (response != nil)
{
if ([[response objectForKey:#"status"] isEqualToString:#"OK"])
{
result = response;
NSLog(#"%#",response);
}
else
{
if (error)
{
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:[response objectForKey:#"status"] forKey:NSLocalizedDescriptionKey];
*error = [[NSError alloc] initWithDomain:#"AppName" code:2 userInfo:details];
}
}
}
else
{
if(error)
{
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:NSLocalizedString(#"ErrorServidor", nil) forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:#"AppName" code:1 userInfo:details];
return nil;
}
}
return result;
}
First off, according to the Google Terms & Conditions you're not allowed to use their directions/data on someone else's maps.
Secondly, the first is partly imposed because people have different data, place roads in different spots, break the roads into different segments etc etc and thus instructions don't line up.
If you want to show directions in your map you'll have to find another source. Maybe you should consider the CloudMade API.
Now you could use Google Maps SDK for iOS. That's the only legal option if you need to display Google Directions API under iOS6.
You can use Mapkit direction request API.
Direction request api has some limitation for consecutive calls made otherwise it works similar as google direction api.
There are ways to fetch direction for driving, walking and transit.
Also there is a way to get alternate routes.
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:SourceCLLocationCorodinate).coordinate addressDictionary:nil];
MKMapItem *sourceMapItem = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark];
[request setSource:sourceMapItem];
MKPlacemark *destPlacemark = [[MKPlacemark alloc] initWithCoordinate:destCLLocationCoordinate addressDictionary:nil];
MKMapItem *destMapItem = [[MKMapItem alloc] initWithPlacemark:destPlacemark];
[request setDestination:destMapItem];
[request setTransportType:MKDirectionsTransportTypeAny];
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
if(![directions isCalculating])
{
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error)
{
// Handle Error
NSLog(#"Error for this particular call");
}
else
{
for (MKRoute * route in response.routes)
{
//Add the route.polyline to the mapkit overlay
}
}];
}
Related
I'm trying to get the data for a selected marker using the following code:
-(void)viewDidLoad {
NSMutableDictionary *viewParams3 = [NSMutableDictionary new];
[viewParams3 setValue:#"breweries" forKey:#"view_name"];
[DIOSView viewGet:viewParams3 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.breweryLocations = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *brewInfo in self.breweryLocations) {
NSString *location = brewInfo[#"address"];
NSString *userNames = brewInfo[#"node_title"];
NSString *firstRemoved = [userNames stringByReplacingOccurrencesOfString:#"'" withString:#""];
NSString *userBio = brewInfo[#"body"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
CLLocationCoordinate2D position = placemark.coordinate;
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.title = firstRemoved;
marker.icon = [UIImage imageNamed:#"brewIconMax"];
marker.map = self.mapView;
marker.userData = self.breweryLocations;
marker.map.selectedMarker.zIndex = index + 1;
}
}
];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
- (BOOL) mapView: (GMSMapView *)mapView didTapMarker:(GMSMarker *)marker
{
self.venueCategory.text = marker.userData[mapView.selectedMarker.zIndex][#"type"];
}
That said, this line of code
self.venueCategory.text = marker.userData[mapView.selectedMarker.zIndex][#"type"];
returns the data from the first dictionary in my array no matter which marker I tap (zIndex is always returned as 0). I can't seem to find the correct code to obtain the selected marker's array data anywhere.
Any idea what that line should look like instead?
It's not clear to me whether "type" is an element of the brewery location dictionary, so I'm taking some guesses here.
I'd suggest setting marker.userData to the brewInfo dictionary, and not the entire breweryLocations array.
marker.userData = brewInfo;
Then this to get the "type" from the brewInfo dictionary.
self.venueCategory.text = marker.userData[#"type"];
Phone number getting like this.
Phone ABMultiValueRef 0x17674380 with 1 value(s)
0: $!!$ (0x176740e0) - 7124779070 (0x176742a0)
How to get this number"7124779070" from the above line.
I'm using this code for ios 7.Is it correct or wrong ,Please sugggest me.
int i;
ABAddressBookRef contactBook = ABAddressBookCreateWithOptions(NULL, NULL);
NSMutableArray *allData = ( NSMutableArray *)(ABAddressBookCopyArrayOfAllPeople(contactBook));
CFIndex contactNum = CFArrayGetCount((__bridge CFArrayRef)(allData));
for (i = 0; i < contactNum; i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex((__bridge CFMutableArrayRef)(allData), i);
NSString* firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString* lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
NSString* phonesNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
// Remove all formatting symbols that might be in both phone number being compared
NSCharacterSet *toExclude = [NSCharacterSet characterSetWithCharactersInString:#"/.()- "];
phonesNum = [[phonesNum componentsSeparatedByCharactersInSet:toExclude] componentsJoinedByString: #""];
NSString *phoneNumber = [[phonesNum componentsSeparatedByCharactersInSet:toExclude] componentsJoinedByString: #""];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
if (firstName!=nil)
{
[dic setObject:(__bridge id)(firstName) forKey:#"firstName"];
}
if (lastName !=nil) {
[dic setObject:(__bridge id)(lastName) forKey:#"lastName"];
}
if (phonesNum!=nil) {
[dic setObject:(__bridge id)(phonesNum) forKey:#"phonesNum"];
}
[arr_Contacts addObject:dic];
NSLog(#"First name %#", firstName);
NSLog(#"Last Name %#", lastName);
NSLog(#"Phone %#", phonesNum);
}
First, request permission:
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status != kABAuthorizationStatusAuthorized && status != kABAuthorizationStatusNotDetermined) {
// tell user to enable contacts in privacy settings
NSLog(#"You previously denied access: You must enable access to contacts in settings");
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
NSLog(#"ABAddressBookCreateWithOptions error: %#", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(#"ABAddressBookRequestAccessWithCompletion error: %#", CFBridgingRelease(error));
}
if (granted) {
[self getContacts:addressBook];
} else {
// tell user to enable contacts in privacy settings
NSLog(#"You just denied access: You must enable access to contacts in settings");
}
CFRelease(addressBook);
});
Second, to retrieve the phone numbers, use ABMultiValueCopyValueAtIndex:
- (void)getContacts:(ABAddressBookRef)addressBook
{
NSArray *allData = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
NSInteger contactCount = [allData count];
for (int i = 0; i < contactCount; i++) {
ABRecordRef person = CFArrayGetValueAtIndex((__bridge CFArrayRef)allData, i);
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
if (firstName) {
dictionary[#"firstName"] = firstName;
}
if (lastName) {
dictionary[#"lastName"] = lastName;
}
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount(phones);
if (phoneNumberCount > 0) {
NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, 0));
dictionary[#"phone"] = phone;
}
// or if you wanted to iterate through all of them, you could do something like:
//
// for (int j = 0; j < phoneNumberCount; j++) {
// NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, j));
//
// // do something with `phone`
// }
if (phones) {
CFRelease(phones);
}
[arr_Contacts addObject:dictionary];
}
}
A couple of additional issues addressed above:
The ABAddressBookCreateWithOptions does not return a mutable array. It's an immutable array. Replace all of those mutable references with immutable.
You must honor the Create Rule, namely that you're responsible for releasing any object returned from a Core Foundation method with either Create or Copy in its name. If the object supports toll-free bridging (e.g. the array of contacts, the first name string, the last name string, etc.), you can transfer ownership to ARC with CFBridgingRelease or __bridge_transfer. If the object doesn't support toll-free bridging (such as the phones or addressBook objects, above), then you must explicitly call CFRelease for the object in question.
Make sure to run your code through the static analyzer (shift+command+B, or choose "Analyze" from Xcode's "Product" menu), and it will identify these sorts of issues for you.
If a function, such as ABAddressBookCreateWithOptions offers an error parameter, you should avail yourself of it. I illustrate the proper use of the CFErrorRef object above.
What do you recive in console from Phone %# NSLog ? if Phone ABMultiValueRef 0x17674380 with 1 value(s) 0: $!!$ (0x176740e0) - 7124779070 (0x176742a0)just substring after '-'
NSString *myString = #"Phone ABMultiValueRef 0x17674380 with 1 value(s) 0: $!!$ (0x176740e0) - 7124779070 (0x176742a0)";
NSArray *myArray = [myString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"-"]];
and this is my method to get phone's
- (void) getContacts
{
NSMutableDictionary *response = [[NSMutableDictionary alloc] init];
ABAddressBookRef contactBook = ABAddressBookCreateWithOptions(NULL, NULL);
arr_Contacts = [[NSMutableArray alloc] init];
ABAddressBookRef allPeople = contactBook;
CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(allPeople);
CFIndex numberOfContacts = ABAddressBookGetPersonCount(allPeople);
NSLog(#"contact == %#",allContacts);
NSLog(#"numberOfContacts------------------------------------%ld",numberOfContacts);
for(int i = 0; i < numberOfContacts; i++){
NSString* name = #"";
NSString* phone = #"";
NSString* email = #"";
ABRecordRef aPerson = CFArrayGetValueAtIndex(allContacts, i);
ABMultiValueRef fnameProperty = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);
ABMultiValueRef lnameProperty = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);
ABMultiValueRef phoneProperty = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);\
ABMultiValueRef emailProperty = ABRecordCopyValue(aPerson, kABPersonEmailProperty);
NSArray *emailArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty);
NSArray *phoneArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneProperty);
if (fnameProperty != nil) {
name = [NSString stringWithFormat:#"%#", fnameProperty];
}
if (lnameProperty != nil) {
name = [name stringByAppendingString:[NSString stringWithFormat:#" %#", lnameProperty]];
}
if ([phoneArray count] > 0) {
if ([phoneArray count] > 1) {
for (int i = 0; i < [phoneArray count]; i++) {
phone = [phone stringByAppendingString:[NSString stringWithFormat:#"%#, ", [phoneArray objectAtIndex:i]]];
}
}else {
phone = [NSString stringWithFormat:#"%#", [phoneArray objectAtIndex:0]];
}
}
if ([emailArray count] > 0) {
if ([emailArray count] > 1) {
for (int i = 0; i < [emailArray count]; i++) {
email = [email stringByAppendingString:[NSString stringWithFormat:#"%#\n", [emailArray objectAtIndex:i]]];
}
}else {
email = [NSString stringWithFormat:#"%#", [emailArray objectAtIndex:0]];
}
}
NSLog(#"NAME : %#",name);
NSLog(#"PHONE: %#",phone);
NSLog(#"EMAIL: %#",email);
NSLog(#"\n");
[response setObject:name forKey:#"name"];
[response setObject:phone forKey:#"phone"];
[response setObject:email forKey:#"email"];
[arr_Contacts addObject:response];
}
}
Cheers
In my app I have a Place entity that contains reviews and featured objects at the minute my app is constantly refreshing these everytime i parse my xml data which is fine however I need to delete the review and featued objects before they are re parsed. My code is as follows and I believe I need to delete the objects in the parseXML method at the top:
-(void)parseXML:(NSString*)xml{
TBXML * tbxml = [TBXML tbxmlWithXMLString:xml];
if(tbxml.rootXMLElement){
[self traverseElement:tbxml.rootXMLElement];
if(self.tempItem){
NSLog(#"Ending Application");
[self configurePlaceChildrenAndSave];
[self startGeoCodingQueue];
}
}
}
-(void)fireGeocoder:(BSForwardGeocoder*)g{
NSLog(#"Begining FGC for %# (%#)",g.searchQuery,g.metaData);
[g findLocation];
}
-(void)startGeoCodingQueue{
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kGeoCoderInProgress];
int i = 0;
BSForwardGeocoder * fgc;
NSArray * a = [CoreDataBasicService fetchResultsForEnity:#"Place" andSortDiscriptor:#"name" Ascending:YES];
for (Place * p in a) {
if(p.latitude && p.longitude)continue;//skip geocoding if location data exists
fgc = [[BSForwardGeocoder alloc] initWithDelegate:self];
fgc.metaData = p.name;
fgc.searchQuery = p.postcode;
NSLog(#"gc:%i-%i",i,[a count]);
if([a count] == i+1){
fgc.last = YES;
}
float delay = (float)i*kGeoCoderDelay;
[self performSelector:#selector(fireGeocoder:) withObject:[fgc autorelease] afterDelay:delay];
fgc = nil;
i++;
}
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:i] forKey:kGeoCoderCompletedKey];
}
-(void)finishedGeocoding{
[[NSUserDefaults standardUserDefaults] setValue:[NSDate date] forKey:kGeoCoderlastRanKey];
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:NO] forKey:kGeoCoderInProgress];
[[NSNotificationCenter defaultCenter] postNotificationName:kGeoCoderNotificationName object:nil];
}
-(void)forwardGeocoderError:(BSForwardGeocoder *)geocoder errorMessage:(NSString *)errorMessage{
NSLog(#"EX ERROR: GEOCODER FAILED - %#",errorMessage);
if(geocoder.last)[self finishedGeocoding];
}
- (void)forwardGeocoderFoundLocation:(BSForwardGeocoder*)geocoder
{
if(geocoder.status == G_GEO_SUCCESS)
{
BSKmlResult *result = [geocoder.results lastObject];
if(!result)return;
//[self.fowardGeocodingQueue setObject:[NSString stringWithString:value] forKey:self.tempItem.name];
Place * p = [CoreDataBasicService fetchPlaceNamed:geocoder.metaData];
p.latitude = [NSNumber numberWithFloat:result.latitude];
p.longitude = [NSNumber numberWithFloat:result.longitude];
[CoreDataBasicService saveChanges];
//NSLog(#"%# - %f,%f",p2.name,p2.latitude,p2.longitude);
NSLog(#"completed Foward geocoding for '%#' (%#) [%f,%f]",geocoder.metaData,geocoder.searchQuery,[p.latitude floatValue],[p.longitude floatValue]);
if(geocoder.last)[self finishedGeocoding];
}
else {
NSString *message = #"";
switch (geocoder.status) {
case G_GEO_BAD_KEY:
message = #"The API key is invalid.";
break;
case G_GEO_UNKNOWN_ADDRESS:
message = [NSString stringWithFormat:#"Could not find %#", geocoder.searchQuery];
break;
case G_GEO_TOO_MANY_QUERIES:
message = #"Too many queries has been made for this API key.";
break;
case G_GEO_SERVER_ERROR:
message = #"Server error, please try again.";
break;
default:
break;
}
NSLog(#"ERROR: GEOCODER FAILED - %#",message);
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Information"
// message:message
// delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles: nil];
// [alert show];
// [alert release];
}
}
-(void)configurePlaceChildrenAndSave{
if(self.tempReviewArray.count==0 && self.tempReview)[self.tempReviewArray addObject:self.tempReview];
if(self.tempFeatureArray.count==0 && self.tempFeature)[self.tempFeatureArray addObject:self.tempFeature];
[self.tempItem setReviews:self.tempReviewArray];
[self.tempItem setFeatured:self.tempFeatureArray];
self.tempReviewArray = nil;
self.tempReview = nil;
self.tempFeatureArray = nil;
self.tempFeature = nil;
[CoreDataBasicService saveChanges];
self.tempItem = nil;
}
-(NSString*)formatKeyForCoreData:(NSString*)elementKey{
return [elementKey stringByReplacingOccurrencesOfString:#"-" withString:#""];
}
-(NSDate*)convertStringDateToDate:(NSString*)stringDate{
NSDateFormatter * df = [[NSDateFormatter alloc] init];
NSLog(#"DATE:%#",stringDate);
[df setDateFormat:#"y-M-d'T'H:m:s'Z'"];
NSDate * d = [df dateFromString:stringDate];
[df release];
return d;
}
-(Place*)getPlaceForName:(NSString*)name{
NSPredicate * pred = [NSPredicate predicateWithFormat:#"name = %#",name];
NSArray * results = [CoreDataBasicService fetchResultsForEnity:#"Place" WithPredicate:pred andSortDiscriptor:#"identifier" Ascending:YES];
return [results lastObject];
}
-(void)traverseElement:(TBXMLElement *)element {
do {
// Display the name of the element
NSString * value = [TBXML textForElement:element];
NSLog(#"%#-'%#'",[TBXML elementName:element],value);
// Obtain first attribute from element
NSString * ele = [TBXML elementName:element];
if([ele isEqualToString:#"place"]){
if(self.tempItem){
//GEOCODER HERE
[self configurePlaceChildrenAndSave];
}
//CREATE NEW CD ITEM HER
if(dataBaseExits){
TBXMLElement * idElement = [TBXML childElementNamed:#"name" parentElement:element];
Place * p = [self getPlaceForName:[NSString stringWithFormat:#"%#",[TBXML textForElement:idElement]]];
if(p){
[self setTempItem:p];
TBXMLElement * reviewsElement = [TBXML childElementNamed:#"reviews" parentElement:element];
if(reviewsElement){
self.tempItem.reviews = nil;
[CoreDataBasicService saveChanges];
[self traverseElement:reviewsElement];
}
TBXMLElement * promosElement = [TBXML childElementNamed:#"featured-places" parentElement:element];
if(promosElement){
self.tempItem.featured = nil;
[CoreDataBasicService saveChanges];
[self traverseElement:promosElement];
}
[CoreDataBasicService saveChanges];
continue;
}
I know it is possible to pull up a contact and see information based on one contact. But is there any way to get all the emails from the contacts you have entered email addresses for and then store that in a NSArray?
This is my first time working with contacts so I don't know much about it.
Yes, you can do this. It seems suspicious that you would want to do this (why do you need this information?), but it isn't difficult to do.
You can use ABAddressBookCopyArrayOfAllPeople to get an CFArrayRef with all of the people, and then you can query kABPersonEmailProperty of each using ABRecordCopyValue. The code would look something like this (untested):
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableArray *allEmails = [[NSMutableArray alloc] initWithCapacity:CFArrayGetCount(people)];
for (CFIndex i = 0; i < CFArrayGetCount(people); i++) {
ABRecordRef person = CFArrayGetValueAtIndex(people, i);
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
for (CFIndex j=0; j < ABMultiValueGetCount(emails); j++) {
NSString* email = (NSString*)ABMultiValueCopyValueAtIndex(emails, j);
[allEmails addObject:email];
[email release];
}
CFRelease(emails);
}
CFRelease(addressBook);
CFRelease(people);
(Memory allocation may be a little off; it's been a while since I've developed Cocoa/Core Foundation code.)
But seriously, question why you are doing this. There's a good chance that there's a better solution by just using the Apple-provided APIs to present a contact picker at appropriate times.
ABAddressBookRef allPeople = ABAddressBookCreate();
CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(allPeople);
CFIndex numberOfContacts = ABAddressBookGetPersonCount(allPeople);
NSLog(#"numberOfContacts------------------------------------%ld",numberOfContacts);
for(int i = 0; i < numberOfContacts; i++){
NSString* name = #"";
NSString* phone = #"";
NSString* email = #"";
ABRecordRef aPerson = CFArrayGetValueAtIndex(allContacts, i);
ABMultiValueRef fnameProperty = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);
ABMultiValueRef lnameProperty = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);
ABMultiValueRef phoneProperty = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);\
ABMultiValueRef emailProperty = ABRecordCopyValue(aPerson, kABPersonEmailProperty);
NSArray *emailArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty);
NSArray *phoneArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneProperty);
if (fnameProperty != nil) {
name = [NSString stringWithFormat:#"%#", fnameProperty];
}
if (lnameProperty != nil) {
name = [name stringByAppendingString:[NSString stringWithFormat:#" %#", lnameProperty]];
}
if ([phoneArray count] > 0) {
if ([phoneArray count] > 1) {
for (int i = 0; i < [phoneArray count]; i++) {
phone = [phone stringByAppendingString:[NSString stringWithFormat:#"%#\n", [phoneArray objectAtIndex:i]]];
}
}else {
phone = [NSString stringWithFormat:#"%#", [phoneArray objectAtIndex:0]];
}
}
if ([emailArray count] > 0) {
if ([emailArray count] > 1) {
for (int i = 0; i < [emailArray count]; i++) {
email = [email stringByAppendingString:[NSString stringWithFormat:#"%#\n", [emailArray objectAtIndex:i]]];
}
}else {
email = [NSString stringWithFormat:#"%#", [emailArray objectAtIndex:0]];
}
}
NSLog(#"NAME : %#",name);
NSLog(#"PHONE: %#",phone);
NSLog(#"EMAIL: %#",email);
NSLog(#"\n");
}
#import AddressBook;
- (void)addressBookInit {
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusDenied || ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusRestricted){
// NSLog(#"Denied");
UIAlertView *cantAddContactAlert = [[UIAlertView alloc] initWithTitle: #"Cannot get contacts" message: #"You must give the app permission to read the contacts first." delegate:nil cancelButtonTitle: #"OK" otherButtonTitles: nil];
[cantAddContactAlert show];
} else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized){
// NSLog(#"Authorized");
[self getEmails];
} else {
// NSLog(#"Not determined");
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!granted){
//4
UIAlertView *cantAddContactAlert = [[UIAlertView alloc] initWithTitle: #"Cannot get contacts" message: #"You must give the app permission to read the contacts first." delegate:nil cancelButtonTitle: #"OK" otherButtonTitles: nil];
[cantAddContactAlert show];
return;
}
// NSLog(#"Authorized 2");
[self getEmails];
});
});
}
}
-(NSArray *)getEmails
{
NSMutableArray *emails = [NSMutableArray array];
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, nil);
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
for (id record in allContacts)
{
ABRecordRef person = (__bridge ABRecordRef)record;
ABMultiValueRef emailProperty = ABRecordCopyValue(person, kABPersonEmailProperty) ;
NSArray *personEmails = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty);
[emails addObjectsFromArray:personEmails];
CFRelease(person);
CFRelease(emailProperty);
}
CFRelease(addressBookRef) ;
for (NSString *email in emails)
{
NSLog(#"%#", email) ;
}
return emails;
}
for iOS 9+, use Contacts framework, Objective C
-(NSArray*)getAllContacts{
__block NSMutableArray *allContacts = nil;
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES) {
//keys with fetching properties
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactEmailAddressesKey, CNContactImageDataKey];
NSString *containerId = store.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(#"error fetching contacts %#", error);
} else {
allContacts = [NSMutableArray array];
for (CNContact *contact in cnContacts) {
// copy data to my custom Contacts class.
// create custom class Contacts with firstName,lastName,image and emailAddress
for (CNLabeledValue<NSString*> *email in contact.emailAddresses) {
Contact *newContact = [[Contact alloc] init];
newContact.firstName = contact.givenName;
newContact.lastName = contact.familyName;
UIImage *image = [UIImage imageWithData:contact.imageData];
newContact.image = image;
newContact.emailAddress = email.value;
[allContacts addObject:newContact];
}
}
}
}
}];
return allContacts;}
I'm really desperate on this one. I'm trying to make a Framework which you can search and play YouTube videos with. But while testing it, I'm running in to a big problem.
In the search operation I'm adding YTVideos (a subclass of NSObject) to a NSMutableArray. When I loop thru it in the main(), I'm getting nil-objects:
Method
- (NSArray *)videosInRange:(NSRange)range {
if(range.length > 50) {
[NSException raise:#"Range lenth > 50"
format:#"The range of -videosInRange: can't be bigger than 50"];
return nil;
}
if((range.location + range.length) > 999) {
[NSException raise:#"Range to big"
format:#"The given range was to big (%d, %d)", range.location, range.length];
return nil;
}
NSString *searchURLString = [[self feedURL] absoluteString];
searchURLString = [searchURLString stringBySettingURLAttribute:#"start-index" value:[NSString stringWithFormat:#"%d",range.location + 1]];
searchURLString = [searchURLString stringBySettingURLAttribute:#"max-results" value:[NSString stringWithFormat:#"%d",range.length]];
NSLog(#"%#",searchURLString);
NSURL *url = [NSURL URLWithString:searchURLString];
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:url
options:0
error:NULL];
if(!xmlDoc)
return nil;
NSArray *videoElements = [[xmlDoc rootElement] elementsForName:#"entry"];
NSMutableArray *videos = [[NSMutableArray alloc] initWithCapacity:[videoElements count]];
register int i;
for(i = 0; i < [videoElements count]; i++) {
NSAutoreleasePool *addPool = [[NSAutoreleasePool alloc] init];
YTVideo *vid = [[YTVideo alloc] initWithXMLElement:[videoElements objectAtIndex:i]];
[videos addObject:vid];
[vid release];
[addPool drain];
}
NSArray *retValue = [NSArray arrayWithArray:videos];
[videos release];
return retValue;
}
main()
int main(int argc, const char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
YTSearchFeed *feed = [[YTSearchFeed alloc] initWithSearch:#"Eminem"];
long long results = [feed videoCount];
NSLog(#"%lld videos for search", results);
long long i = 0;
while(results != 0) {
int length = (results >= 50) ? (50) : (results);
NSArray *videos = [feed videosInRange:NSMakeRange(i, length)];
NSLog(#"L: %d", [videos count]);
int z;
for(z = 0; z < [videos count]; z++, i++) {
YTVideo *vid = [videos objectAtIndex:z];
NSString *title = [vid title];
NSLog(#"%d: %#", i+1, title);
}
results -= length;
}
[pool drain];
return NSApplicationMain(argc, argv);
}
I hope someone can take the time to look at this, and if you need anymore information, just ask.
Thank you in advance,
ief2
EDIT: YTVideo
- (id)initWithXMLElement:(NSXMLElement *)element {
self = [super init];
if(self != nil) {
_XMLElement = [element copy];
}
return self;
}
- (NSString *)title {
if(!_title) {
NSString *str = [[[self XMLElement] firstElementWithName:#"title"] stringValue];
_title = [[str stringByDecodingHTMLEntities] retain];
}
return [[_title copy] autorelease];
}
I get the title (and other video information) only when it's requested. the -stringByDecodingHTMLEntities works fine (Category on NSString).
I've rewritten the code and initialized all instance variables in the -initmethod