From 6866fdcf1bc56fbbbeddbe4308c8d9305e4784d4 Mon Sep 17 00:00:00 2001 From: Felix Dumit Date: Sat, 7 Mar 2015 19:07:58 -0300 Subject: [PATCH 1/3] support for place photos and streetview photos --- .../FTGooglePlacesAPISearchResultItem.h | 1 + .../FTGooglePlacesAPISearchResultItem.m | 1 + FTGooglePlacesAPI/FTGooglePlacesAPIService.h | 45 +++++++++++++++++++ FTGooglePlacesAPI/FTGooglePlacesAPIService.m | 30 +++++++++++++ 4 files changed, 77 insertions(+) diff --git a/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.h b/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.h index ea45582..0c81049 100644 --- a/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.h +++ b/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.h @@ -55,6 +55,7 @@ typedef NS_ENUM(NSUInteger, FTGooglePlacesAPISearchResultItemOpenedState) { @property (nonatomic, assign, readonly) CGFloat rating; @property (nonatomic, strong, readonly) NSString *reference; @property (nonatomic, strong, readonly) NSArray *types; +@property (nonatomic, strong, readonly) NSArray *photos; /** * You can access complete response dictionary using this property. diff --git a/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.m b/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.m index 7808593..f4c6e79 100644 --- a/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.m +++ b/FTGooglePlacesAPI/FTGooglePlacesAPISearchResultItem.m @@ -149,6 +149,7 @@ - (void)ftgpi_importDictionary:(NSDictionary *)dictionary _reference = [dictionary ftgp_nilledObjectForKey:@"reference"]; _types = [dictionary ftgp_nilledObjectForKey:@"types"]; + _photos = [dictionary ftgp_nilledObjectForKey:@"photos"]; // Deprecated, left for backwards compatibility _itemId = [dictionary ftgp_nilledObjectForKey:@"id"]; } diff --git a/FTGooglePlacesAPI/FTGooglePlacesAPIService.h b/FTGooglePlacesAPI/FTGooglePlacesAPIService.h index efa1cb8..df0b82a 100644 --- a/FTGooglePlacesAPI/FTGooglePlacesAPIService.h +++ b/FTGooglePlacesAPI/FTGooglePlacesAPIService.h @@ -29,6 +29,7 @@ #import #import "FTGooglePlacesAPICommon.h" +#import "FTGooglePlacesAPISearchResultItem.h" @class FTGooglePlacesAPISearchResponse; @class FTGooglePlacesAPIDetailResponse; @@ -68,6 +69,50 @@ typedef void (^FTGooglePlacesAPIDetailRequestCompletionhandler)(FTGooglePlacesAP */ + (void)registerSearchResultItemClass:(Class)itemClass; +/** + * Return list of photo urls + * + * @param item search result item + * + * @return array of photo urls + */ ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item; + +/** + * List of photo urls for a given item + * + * @param item search result item + * @param maxWidth max width of photo + * + * @return array of photo urls + */ ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item maxWidth:(NSInteger)maxWidth; + + +/** + * Returns the url for a given photo reference + * + * @param reference photo reference + * @param maxWidth maximiun width + * + * @return photo url + */ ++ (NSString *)photoURLForPhotoReference:(NSString *)reference maxWidth:(NSInteger)maxWidth; + + +/** + * Return photo url for streetview of location + * + * @param coordinate location coordinate + * @param maxWidth max width of photo + * + * @return string url of streetview photo + */ ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate maxWidth:(NSInteger)maxWidth; + ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate; + + /** * Asks the service to execute the given Google Places API Places Search request. * diff --git a/FTGooglePlacesAPI/FTGooglePlacesAPIService.m b/FTGooglePlacesAPI/FTGooglePlacesAPIService.m index e131bca..8db8d66 100644 --- a/FTGooglePlacesAPI/FTGooglePlacesAPIService.m +++ b/FTGooglePlacesAPI/FTGooglePlacesAPIService.m @@ -49,6 +49,8 @@ NSString *const FTGooglePlacesAPIBaseURL = @"https://maps.googleapis.com/maps/api/place/"; +NSString *const FTGooglePlaceAPIPhotoURL = @"https://maps.googleapis.com/maps/api/place/photo?key=%@&maxwidth=%@&photoreference=%@"; +NSString *const FTGooglePlaceStreetViewAPIURL = @"https://maps.googleapis.com/maps/api/streetview?key=%@&location=%@&size=%@"; static BOOL FTGooglePlacesAPIDebugLoggingEnabled; @@ -151,6 +153,34 @@ + (void)registerSearchResultItemClass:(Class)itemClass [[[self class] sharedService] setSearchResultsItemClass:itemClass]; } ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item maxWidth:(NSInteger)maxWidth { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:item.photos.count]; + for (NSDictionary *photo in item.photos) { + NSInteger width = MIN(maxWidth, [[photo objectForKey:@"width"] integerValue]); + NSString *photoReference = [photo objectForKey:@"photo_reference"]; + [array addObject:[self photoURLForPhotoReference:photoReference maxWidth:width]]; + } + return array; +} + ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item { + return [[self class] photoURLsForPlace:item maxWidth:10000]; +} + ++ (NSString *)photoURLForPhotoReference:(NSString *)reference maxWidth:(NSInteger)maxWidth { + return [NSString stringWithFormat:FTGooglePlaceAPIPhotoURL, [self sharedService].apiKey, @(maxWidth), reference]; +} + ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate { + return [self streetViewPhotoURLForLocation:coordinate maxWidth:1000]; +} + ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate maxWidth:(NSInteger)maxWidth { + NSString *locationString = [NSString stringWithFormat:@"%@,%@", @(coordinate.latitude), @(coordinate.longitude)]; + NSString *sizeString = [NSString stringWithFormat:@"%@x%@", @(maxWidth), @(maxWidth)]; + return [NSString stringWithFormat:FTGooglePlaceStreetViewAPIURL, [self sharedService].apiKey, locationString, sizeString]; +} + + (void)executeSearchRequest:(id)request withCompletionHandler:(FTGooglePlacesAPISearchRequestCompletionHandler)completion { From 86a431ccac6d185eaf232153aea5cc11769db1d8 Mon Sep 17 00:00:00 2001 From: Felix Dumit Date: Tue, 16 Aug 2016 18:34:38 -0700 Subject: [PATCH 2/3] Update FTGooglePlacesAPI.podspec --- FTGooglePlacesAPI.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FTGooglePlacesAPI.podspec b/FTGooglePlacesAPI.podspec index 1ceb609..748f628 100644 --- a/FTGooglePlacesAPI.podspec +++ b/FTGooglePlacesAPI.podspec @@ -23,6 +23,6 @@ Pod::Spec.new do |s| :tag => s.version.to_s } s.source_files = 'FTGooglePlacesAPI/*.{h,m}' s.requires_arc = true - s.dependency 'AFNetworking', '~> 2.2' + s.dependency 'AFNetworking' end From c80ba030455efc958395f197c5500dfc36449447 Mon Sep 17 00:00:00 2001 From: Felix Dumit Date: Tue, 16 Aug 2016 18:40:30 -0700 Subject: [PATCH 3/3] update afnetworking --- FTGooglePlacesAPI/FTGooglePlacesAPIService.m | 178 ++++++++++--------- 1 file changed, 94 insertions(+), 84 deletions(-) diff --git a/FTGooglePlacesAPI/FTGooglePlacesAPIService.m b/FTGooglePlacesAPI/FTGooglePlacesAPIService.m index 8db8d66..d74b029 100644 --- a/FTGooglePlacesAPI/FTGooglePlacesAPIService.m +++ b/FTGooglePlacesAPI/FTGooglePlacesAPIService.m @@ -28,7 +28,7 @@ #import "FTGooglePlacesAPIService.h" -#import "AFNetworking.h" +#import #import "FTGooglePlacesAPISearchResponse.h" #import "FTGooglePlacesAPIDetailResponse.h" @@ -41,9 +41,9 @@ * @param ... Output string parameters */ #ifdef DEBUG - #define FTGPServiceLog(format, ...) if (FTGooglePlacesAPIDebugLoggingEnabled) { NSLog(format, ##__VA_ARGS__); } +#define FTGPServiceLog(format, ...) if (FTGooglePlacesAPIDebugLoggingEnabled) { NSLog(format, ## __VA_ARGS__); } #else - #define FTGPServiceLog(format, ...) ((void)0) +#define FTGPServiceLog(format, ...) ((void)0) #endif @@ -66,7 +66,7 @@ @interface FTGooglePlacesAPIService () * AFNetworking request manager. This manager is lazily intitialized in custom getter. * Default implementation is initialized with base URL of Google Places API */ -@property (nonatomic, strong) AFHTTPRequestOperationManager *httpRequestOperationManager; +@property (nonatomic, strong) AFHTTPSessionManager *httpRequestOperationManager; @property (nonatomic, copy) NSString *apiKey; @property (nonatomic, weak) Class searchResultsItemClass; @@ -84,7 +84,7 @@ + (FTGooglePlacesAPIService *)sharedService; */ @interface FTGooglePlacesAPIService (Private) -+ (NSError *)ftgp_errorForResponseStatus:(FTGooglePlacesAPIResponseStatus)status; ++ (NSError *) ftgp_errorForResponseStatus:(FTGooglePlacesAPIResponseStatus)status; @end @@ -101,6 +101,7 @@ + (FTGooglePlacesAPIService *)sharedService static FTGooglePlacesAPIService *SharedInstance; static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ SharedInstance = [[FTGooglePlacesAPIService alloc] init]; }); @@ -111,11 +112,13 @@ + (FTGooglePlacesAPIService *)sharedService - (id)init { self = [super init]; + if (self) { _apiKey = nil; _searchResultsItemClass = nil; FTGooglePlacesAPIDebugLoggingEnabled = NO; } + return self; } @@ -129,12 +132,11 @@ - (void)setApiKey:(NSString *)apiKey #pragma mark Private -- (AFHTTPRequestOperationManager *)httpRequestOperationManager +- (AFHTTPSessionManager *)httpRequestOperationManager { - if (!_httpRequestOperationManager) - { + if (!_httpRequestOperationManager) { NSURL *baseUrl = [NSURL URLWithString:FTGooglePlacesAPIBaseURL]; - _httpRequestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseUrl]; + _httpRequestOperationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseUrl]; _httpRequestOperationManager.requestSerializer = [AFHTTPRequestSerializer serializer]; } @@ -153,90 +155,103 @@ + (void)registerSearchResultItemClass:(Class)itemClass [[[self class] sharedService] setSearchResultsItemClass:itemClass]; } -+ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item maxWidth:(NSInteger)maxWidth { ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item maxWidth:(NSInteger)maxWidth +{ NSMutableArray *array = [NSMutableArray arrayWithCapacity:item.photos.count]; + for (NSDictionary *photo in item.photos) { NSInteger width = MIN(maxWidth, [[photo objectForKey:@"width"] integerValue]); NSString *photoReference = [photo objectForKey:@"photo_reference"]; [array addObject:[self photoURLForPhotoReference:photoReference maxWidth:width]]; } + return array; } -+ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item { ++ (NSArray *)photoURLsForPlace:(FTGooglePlacesAPISearchResultItem *)item +{ return [[self class] photoURLsForPlace:item maxWidth:10000]; } -+ (NSString *)photoURLForPhotoReference:(NSString *)reference maxWidth:(NSInteger)maxWidth { - return [NSString stringWithFormat:FTGooglePlaceAPIPhotoURL, [self sharedService].apiKey, @(maxWidth), reference]; ++ (NSString *)photoURLForPhotoReference:(NSString *)reference maxWidth:(NSInteger)maxWidth +{ + NSString *sizeS = maxWidth > 0 ? @(maxWidth).description : @"%@"; + + return [NSString stringWithFormat:FTGooglePlaceAPIPhotoURL, [self sharedService].apiKey, sizeS, reference]; } -+ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate { ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate +{ return [self streetViewPhotoURLForLocation:coordinate maxWidth:1000]; } -+ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate maxWidth:(NSInteger)maxWidth { ++ (NSString *)streetViewPhotoURLForLocation:(CLLocationCoordinate2D)coordinate maxWidth:(NSInteger)maxWidth +{ NSString *locationString = [NSString stringWithFormat:@"%@,%@", @(coordinate.latitude), @(coordinate.longitude)]; - NSString *sizeString = [NSString stringWithFormat:@"%@x%@", @(maxWidth), @(maxWidth)]; + NSString *sizeString = maxWidth > 0 ? [NSString stringWithFormat:@"%@x%@", @(maxWidth), @(maxWidth)] : @"%1$@x%1$@"; + return [NSString stringWithFormat:FTGooglePlaceStreetViewAPIURL, [self sharedService].apiKey, locationString, sizeString]; } -+ (void)executeSearchRequest:(id)request ++ (void)executeSearchRequest:(id )request withCompletionHandler:(FTGooglePlacesAPISearchRequestCompletionHandler)completion { - [[self class] executeRequest:request withCompletionHandler:^(NSDictionary *responseObject, NSError *error) { - - // Networing, parsing or other general error - if (error) { - completion(nil, error); - return; - } - - // Parse response - Class resultsItemClass = [[[self class] sharedService] searchResultsItemClass]; - - FTGooglePlacesAPISearchResponse *response = [[FTGooglePlacesAPISearchResponse alloc] initWithDictionary:responseObject request:request resultsItemClass:resultsItemClass]; - - FTGPServiceLog(@"%@ received Search response. Status: %@, number of results: %ld", [self class], [FTGooglePlacesAPISearchResponse localizedNameOfStatus:response.status], (unsigned long)[response.results count]); - - // Check if everything went OK - if (response && response.status == FTGooglePlacesAPIResponseStatusOK) { - completion(response, nil); - } - // If network request was successfull, but Google Places API - // responded with error status code - else { - completion(response, [[self class] ftgp_errorForResponseStatus:response.status]); - } - }]; + [[self class] executeRequest:request + withCompletionHandler: ^(NSDictionary *responseObject, NSError *error) { + // Networing, parsing or other general error + if (error) { + completion(nil, error); + return; + } + + // Parse response + Class resultsItemClass = [[[self class] sharedService] searchResultsItemClass]; + + FTGooglePlacesAPISearchResponse *response = [[FTGooglePlacesAPISearchResponse alloc] initWithDictionary:responseObject + request:request + resultsItemClass:resultsItemClass]; + + FTGPServiceLog(@"%@ received Search response. Status: %@, number of results: %ld", [self class], [FTGooglePlacesAPISearchResponse localizedNameOfStatus:response.status], (unsigned long)[response.results count]); + + // Check if everything went OK + if (response && response.status == FTGooglePlacesAPIResponseStatusOK) { + completion(response, nil); + } + // If network request was successfull, but Google Places API + // responded with error status code + else { + completion(response, [[self class] ftgp_errorForResponseStatus:response.status]); + } + }]; } -+ (void)executeDetailRequest:(id)request ++ (void)executeDetailRequest:(id )request withCompletionHandler:(FTGooglePlacesAPIDetailRequestCompletionhandler)completion { - [[self class] executeRequest:request withCompletionHandler:^(NSDictionary *responseObject, NSError *error) { - - // Networing, parsing or other general error - if (error) { - completion(nil, error); - return; - } - - // Try to parse response to object - FTGooglePlacesAPIDetailResponse *response = [[FTGooglePlacesAPIDetailResponse alloc] initWithDictionary:responseObject request:request]; - - FTGPServiceLog(@"%@ received Detail response. Status: %@", [self class], [FTGooglePlacesAPISearchResponse localizedNameOfStatus:response.status]); - - // Check if everything went OK - if (response && response.status == FTGooglePlacesAPIResponseStatusOK) { - completion(response, nil); - } - // If network request was successfull, but Google Places API - // responded with error status code - else { - completion(response, [[self class] ftgp_errorForResponseStatus:response.status]); - } - }]; + [[self class] executeRequest:request + withCompletionHandler: ^(NSDictionary *responseObject, NSError *error) { + // Networing, parsing or other general error + if (error) { + completion(nil, error); + return; + } + + // Try to parse response to object + FTGooglePlacesAPIDetailResponse *response = [[FTGooglePlacesAPIDetailResponse alloc] initWithDictionary:responseObject + request:request]; + + FTGPServiceLog(@"%@ received Detail response. Status: %@", [self class], [FTGooglePlacesAPISearchResponse localizedNameOfStatus:response.status]); + + // Check if everything went OK + if (response && response.status == FTGooglePlacesAPIResponseStatusOK) { + completion(response, nil); + } + // If network request was successfull, but Google Places API + // responded with error status code + else { + completion(response, [[self class] ftgp_errorForResponseStatus:response.status]); + } + }]; } + (void)setDebugLoggingEnabled:(BOOL)enabled @@ -246,8 +261,8 @@ + (void)setDebugLoggingEnabled:(BOOL)enabled #pragma mark - Private class methods -+ (void)executeRequest:(id)request - withCompletionHandler:(void(^)(NSDictionary *responseObject, NSError *error))completion ++ (void) executeRequest:(id )request + withCompletionHandler:(void (^)(NSDictionary *responseObject, NSError *error))completion { NSAssert(completion, @"You must provide completion block for the Google Places API request execution. Performing request without handling does not make any sense."); @@ -269,21 +284,16 @@ + (void)executeRequest:(id)request NSString *requestPath = [NSString stringWithFormat:@"%@/json", [request placesAPIRequestMethod]]; // Perform request using AFNetworking - AFHTTPRequestOperationManager *manager = service.httpRequestOperationManager; + AFHTTPSessionManager *manager = service.httpRequestOperationManager; // Perform request - [manager GET:requestPath - parameters:params - success:^(AFHTTPRequestOperation *operation, id responseObject) - { - FTGPServiceLog(@"%@ request SUCCESS (Request URL: %@)", [self class], operation.request.URL); - completion(responseObject, nil); - } - failure:^(AFHTTPRequestOperation *operation, NSError *error) - { - FTGPServiceLog(@"%@ request FAILURE: (Request URL: %@, Error: %@)", [self class], operation.request.URL, error); - completion(nil, error); - }]; + [manager GET:requestPath parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { + FTGPServiceLog(@"%@ request SUCCESS (Request URL: %@)", [self class], task.originalRequest.URL); + completion(responseObject, nil); + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { + FTGPServiceLog(@"%@ request FAILURE: (Request URL: %@, Error: %@)", [self class], task.originalRequest.URL, error); + completion(nil, error); + }]; } @end @@ -295,9 +305,9 @@ @implementation FTGooglePlacesAPIService (Private) + (NSError *)ftgp_errorForResponseStatus:(FTGooglePlacesAPIResponseStatus)status { NSDictionary *userInfo = @{ - NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Google Places API request failed", nil), - NSLocalizedDescriptionKey: [FTGooglePlacesAPIResponse localizedDescriptionForStatus:status] - }; + NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Google Places API request failed", nil), + NSLocalizedDescriptionKey: [FTGooglePlacesAPIResponse localizedDescriptionForStatus:status] + }; return [NSError errorWithDomain:FTGooglePlacesAPIErrorDomain code:status userInfo:userInfo]; }