diff --git a/Classes/App.h b/Classes/App.h deleted file mode 100644 index cad9da5..0000000 --- a/Classes/App.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * App.h - * TTRemoteExamples - * - * Created by Keith Lazuka on 7/25/09. - * - */ - -/* - * NOTE: this is where you can switch the web service between Flickr and Yahoo - * and between using the JSON and XML response processors. - * All you need to do is set SearchServiceDefault and - * SearchResponseFormatDefault to the appropriate value. - * - */ -typedef enum { - SearchServiceYahoo, - SearchServiceFlickr, - SearchServiceDefault = SearchServiceFlickr -} SearchService; -extern SearchService CurrentSearchService; - -typedef enum { - SearchResponseFormatJSON, - SearchResponseFormatXML, - SearchResponseFormatDefault = SearchResponseFormatXML -} SearchResponseFormat; -extern SearchResponseFormat CurrentSearchResponseFormat; - -id CreateSearchModelWithCurrentSettings(void); -id CreateSearchModel(SearchService service, SearchResponseFormat responseFormat); diff --git a/Classes/AppDelegate.m b/Classes/AppDelegate.m index f0fced1..bde2153 100644 --- a/Classes/AppDelegate.m +++ b/Classes/AppDelegate.m @@ -7,37 +7,8 @@ #import "AppDelegate.h" #import "SearchTableViewController.h" #import "SearchPhotosViewController.h" -#import "YahooSearchResultsModel.h" -#import "FlickrSearchResultsModel.h" -#import "App.h" #import "Three20/Three20.h" -SearchService CurrentSearchService = SearchServiceDefault; -SearchResponseFormat CurrentSearchResponseFormat = SearchResponseFormatDefault; - -id CreateSearchModel(SearchService service, SearchResponseFormat responseFormat) -{ - id model = nil; - switch ( service ) { - case SearchServiceYahoo: - model = [[[YahooSearchResultsModel alloc] initWithResponseFormat:responseFormat] autorelease]; - break; - case SearchServiceFlickr: - model = [[[FlickrSearchResultsModel alloc] initWithResponseFormat:responseFormat] autorelease]; - break; - default: - [NSException raise:@"CurrentSearchService unknown" format:nil]; - break; - } - return model; -} - -id CreateSearchModelWithCurrentSettings(void) -{ - return CreateSearchModel(CurrentSearchService, CurrentSearchResponseFormat); -} - - @implementation AppDelegate @synthesize window; diff --git a/Classes/FlickrSearchResultsModel.h b/Classes/FlickrSearchResultsModel.h index bd2c5d8..dd8497a 100644 --- a/Classes/FlickrSearchResultsModel.h +++ b/Classes/FlickrSearchResultsModel.h @@ -6,7 +6,7 @@ // #import "Three20/Three20.h" -#import "App.h" +#import "SearchResultsModel.h" @class URLModelResponse; @@ -17,17 +17,13 @@ * See the description of YahooSearchResultsModel. * */ -@interface FlickrSearchResultsModel : TTURLRequestModel +@interface FlickrSearchResultsModel : TTURLRequestModel { URLModelResponse *responseProcessor; NSString *searchTerms; NSUInteger page; } -@property (nonatomic, readonly) NSArray *results; // When your TTTableViewDataSource needs data to display, it should use this method to acquire the parsed SearchResult domain objects. -@property (nonatomic, readonly) NSUInteger totalResultsAvailableOnServer; -@property (nonatomic, retain) NSString *searchTerms; - -- (id)initWithResponseFormat:(SearchResponseFormat)responseFormat; +// The designated initializer is defined in the SearchResultsModel protocol. @end diff --git a/Classes/FlickrSearchResultsModel.m b/Classes/FlickrSearchResultsModel.m index a7636d5..341ee45 100644 --- a/Classes/FlickrSearchResultsModel.m +++ b/Classes/FlickrSearchResultsModel.m @@ -9,7 +9,6 @@ #import "FlickrJSONResponse.h" #import "FlickrXMLResponse.h" #import "GTMNSDictionary+URLArguments.h" -#import "App.h" const static NSUInteger kFlickrBatchSize = 16; // The number of results to pull down with each request to the server. @@ -61,7 +60,7 @@ - (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more @"flickr.photos.search", @"method", searchTerms, @"text", @"url_m,url_t", @"extras", - @"43f122b1a7fef3db2328bd75b38da08d", @"api_key", // TODO comment this out + @"43f122b1a7fef3db2328bd75b38da08d", @"api_key", // I am providing my own API key as a convenience because I'm trusting you not to use it for evil. [responseProcessor format], @"format", [NSString stringWithFormat:@"%lu", (unsigned long)page], @"page", batchSize, @"per_page", diff --git a/Classes/SearchPhotosViewController.m b/Classes/SearchPhotosViewController.m index 579f4c3..9691428 100644 --- a/Classes/SearchPhotosViewController.m +++ b/Classes/SearchPhotosViewController.m @@ -4,7 +4,7 @@ #import "SearchPhotosViewController.h" #import "SearchResultsPhotoSource.h" -#import "App.h" +#import "SearchResultsModel.h" @implementation SearchPhotosViewController @@ -21,12 +21,16 @@ - (void)doSearch { NSLog(@"Searching for %@", queryField.text); - // Configure the photo source with the user's search terms - // and load the new data. - // NOTE: the compiler warning here is wrong, it just doesn't know - // that photoSource forwards to the model. - [photoSource setSearchTerms:[queryField text]]; [queryField resignFirstResponder]; + + // Configure the photo source with the user's search terms. + // NOTE: I have to explicitly cast the photoSource to the SearchResultsModel + // protocol because otherwise the compiler will issue a warning + // (because the compiler doesn't know that the photoSource forwards + // to a SearchResultsModel at runtime) + [(id)photoSource setSearchTerms:[queryField text]]; + + // Load the new data [photoSource load:TTURLRequestCachePolicyDefault more:NO]; // Display the updated photoSource. diff --git a/Classes/SearchResultsModel.h b/Classes/SearchResultsModel.h new file mode 100644 index 0000000..7c58d77 --- /dev/null +++ b/Classes/SearchResultsModel.h @@ -0,0 +1,54 @@ +/* + * SearchResultsModel.h + * + * Created by Keith Lazuka on 7/25/09. + * + */ + +#import "Three20/Three20.h" + +/* + * NOTE: this is where you can switch the web service between Flickr and Yahoo + * and between using the JSON and XML response processors. + * All you need to do is set SearchServiceDefault and + * SearchResponseFormatDefault to the appropriate value. + * + */ +typedef enum { + SearchServiceYahoo, + SearchServiceFlickr, + SearchServiceDefault = SearchServiceYahoo +} SearchService; +extern SearchService CurrentSearchService; + +typedef enum { + SearchResponseFormatJSON, + SearchResponseFormatXML, + SearchResponseFormatDefault = SearchResponseFormatXML +} SearchResponseFormat; +extern SearchResponseFormat CurrentSearchResponseFormat; + +#pragma mark - + +/* + * SearchResultsModel + * + * This protocol is intended for TTModels that represent a remote search service. + * + */ +@protocol SearchResultsModel + +@property (nonatomic, readonly) NSArray *results; // A list of domain objects constructed by the model after parsing the web service's HTTP response. In this case, it is a list of SearchResult objects. +@property (nonatomic, readonly) NSUInteger totalResultsAvailableOnServer; // The total number of results available on the server (but not necessarily downloaded) for the current model configuration's search query. +@property (nonatomic, retain) NSString *searchTerms; // The keywords that will be submitted to the web service in order to do the actual image search (e.g. "green apple") + +- (id)initWithResponseFormat:(SearchResponseFormat)responseFormat; // The designated initializer + +@end + +#pragma mark - + +// Factory methods for instantiating a functioning SearchResultsModel. +id CreateSearchModelWithCurrentSettings(void); +id CreateSearchModel(SearchService service, SearchResponseFormat responseFormat); + diff --git a/Classes/SearchResultsModel.m b/Classes/SearchResultsModel.m new file mode 100644 index 0000000..33f241e --- /dev/null +++ b/Classes/SearchResultsModel.m @@ -0,0 +1,34 @@ +// +// SearchResultsModel.m +// +// Created by Keith Lazuka on 7/25/09. +// + +#import "SearchResultsModel.h" +#import "YahooSearchResultsModel.h" +#import "FlickrSearchResultsModel.h" + +SearchService CurrentSearchService = SearchServiceDefault; +SearchResponseFormat CurrentSearchResponseFormat = SearchResponseFormatDefault; + +id CreateSearchModel(SearchService service, SearchResponseFormat responseFormat) +{ + id model = nil; + switch ( service ) { + case SearchServiceYahoo: + model = [[[YahooSearchResultsModel alloc] initWithResponseFormat:responseFormat] autorelease]; + break; + case SearchServiceFlickr: + model = [[[FlickrSearchResultsModel alloc] initWithResponseFormat:responseFormat] autorelease]; + break; + default: + [NSException raise:@"CurrentSearchService unknown" format:nil]; + break; + } + return model; +} + +id CreateSearchModelWithCurrentSettings(void) +{ + return CreateSearchModel(CurrentSearchService, CurrentSearchResponseFormat); +} \ No newline at end of file diff --git a/Classes/SearchResultsPhotoSource.h b/Classes/SearchResultsPhotoSource.h index 9747a41..c3a8027 100644 --- a/Classes/SearchResultsPhotoSource.h +++ b/Classes/SearchResultsPhotoSource.h @@ -7,7 +7,7 @@ #import "Three20/Three20.h" -@class YahooSearchResultsModel; +@protocol SearchResultsModel; /* * SearchResultsPhotoSource @@ -28,15 +28,15 @@ */ @interface SearchResultsPhotoSource : NSObject { - YahooSearchResultsModel *model; + id *model; // Backing storage for TTPhotoSource properties. NSString *albumTitle; int totalNumberOfPhotos; } -- (id)initWithModel:(YahooSearchResultsModel *)theModel; // Designated initializer. +- (id)initWithModel:(id)theModel; // Designated initializer. -- (id)underlyingModel; // The model to which this PhotoSource forwards in order to conform to the TTModel protocol. +- (id)underlyingModel; // The model to which this PhotoSource forwards in order to conform to the TTModel protocol. @end diff --git a/Classes/SearchResultsTableDataSource.m b/Classes/SearchResultsTableDataSource.m index 464b46b..71580a5 100644 --- a/Classes/SearchResultsTableDataSource.m +++ b/Classes/SearchResultsTableDataSource.m @@ -7,6 +7,7 @@ #import "SearchResultsTableDataSource.h" #import "SearchResult.h" +#import "SearchResultsModel.h" @implementation SearchResultsTableDataSource @@ -19,7 +20,7 @@ - (void)tableViewDidLoadModel:(UITableView *)tableView // Construct an object that is suitable for the table view system // from each SearchResult domain object that we retrieve from the TTModel. - for (SearchResult *result in [self.model results]) + for (SearchResult *result in [(id)self.model results]) [self.items addObject:[TTTableImageItem itemWithText:result.title imageURL:result.thumbnailURL defaultImage:[UIImage imageNamed:@"photo_placeholder.png"] diff --git a/Classes/SearchTableViewController.m b/Classes/SearchTableViewController.m index c899c66..9335b8c 100644 --- a/Classes/SearchTableViewController.m +++ b/Classes/SearchTableViewController.m @@ -4,7 +4,7 @@ #import "SearchTableViewController.h" #import "SearchResultsTableDataSource.h" -#import "App.h" +#import "SearchResultsModel.h" @implementation SearchTableViewController @@ -63,7 +63,7 @@ - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar // Configure our TTModel with the user's search terms // and tell the TTModelViewController to reload. [searchBar resignFirstResponder]; - [self.model setSearchTerms:[searchBar text]]; // TODO I guess I'm going to need to create a model base class, or at least a protocol. + [(id)self.model setSearchTerms:[searchBar text]]; [self reload]; [self.tableView scrollToTop:YES]; } diff --git a/Classes/YahooSearchResultsModel.h b/Classes/YahooSearchResultsModel.h index 62f39f9..8f667b6 100644 --- a/Classes/YahooSearchResultsModel.h +++ b/Classes/YahooSearchResultsModel.h @@ -6,6 +6,7 @@ // #import "Three20/Three20.h" +#import "SearchResultsModel.h" @class URLModelResponse; @@ -40,15 +41,13 @@ * directly into the YahooSearchResultsModel class. * */ -@interface YahooSearchResultsModel : TTURLRequestModel +@interface YahooSearchResultsModel : TTURLRequestModel { URLModelResponse *responseProcessor; NSString *searchTerms; NSUInteger recordOffset; } -@property (nonatomic, readonly) NSArray *results; // When your TTTableViewDataSource needs data to display, it should use this method to acquire the parsed SearchResult domain objects. -@property (nonatomic, readonly) NSUInteger totalResultsAvailableOnServer; -@property (nonatomic, retain) NSString *searchTerms; +// The designated initializer is defined in the SearchResultsModel protocol. @end diff --git a/Classes/YahooSearchResultsModel.m b/Classes/YahooSearchResultsModel.m index b86a75e..2022ab8 100644 --- a/Classes/YahooSearchResultsModel.m +++ b/Classes/YahooSearchResultsModel.m @@ -9,7 +9,6 @@ #import "YahooJSONResponse.h" #import "YahooXMLResponse.h" #import "GTMNSDictionary+URLArguments.h" -#import "App.h" const static NSUInteger kYahooBatchSize = 16; // The number of results to pull down with each request to the server. diff --git a/Classes/YahooXMLResponse.m b/Classes/YahooXMLResponse.m index 82597e0..4510550 100644 --- a/Classes/YahooXMLResponse.m +++ b/Classes/YahooXMLResponse.m @@ -31,7 +31,7 @@ - (NSError*)request:(TTURLRequest*)request processResponse:(NSHTTPURLResponse*)r NSArray *bigImageWidths = [root nodesForXPath:@"//foo:Result/foo:Width" error:&error]; NSArray *bigImageHeights = [root nodesForXPath:@"//foo:Result/foo:Height" error:&error]; NSArray *thumbnailURLs = [root nodesForXPath:@"//foo:Result/foo:Thumbnail/foo:Url" error:&error]; - totalObjectsAvailableOnServer = [[[[root nodesForXPath:@"foo:ResultSet[@totalResultsAvailable]" error:&error] lastObject] stringValue] integerValue]; + totalObjectsAvailableOnServer = [[[[root nodesForXPath:@"//foo:ResultSet/@totalResultsAvailable" error:&error] lastObject] stringValue] integerValue]; NSAssert1(!error, @"XML Parse error: %@", error); NSAssert([titles count] == [bigImageURLs count] && [titles count] == [thumbnailURLs count], @@ -43,8 +43,8 @@ - (NSError*)request:(TTURLRequest*)request processResponse:(NSHTTPURLResponse*)r result.title = [[titles objectAtIndex:i] stringValue]; result.bigImageURL = [[bigImageURLs objectAtIndex:i] stringValue]; result.thumbnailURL = [[thumbnailURLs objectAtIndex:i] stringValue]; - result.bigImageSize = CGSizeMake([[bigImageWidths objectAtIndex:i] intValue], - [[bigImageHeights objectAtIndex:i] intValue]); + result.bigImageSize = CGSizeMake([[[bigImageWidths objectAtIndex:i] stringValue] intValue], + [[[bigImageHeights objectAtIndex:i] stringValue] intValue]); [self.objects addObject:result]; } diff --git a/TTRemoteExamples.xcodeproj/project.pbxproj b/TTRemoteExamples.xcodeproj/project.pbxproj index f0e94fb..1490b7e 100755 --- a/TTRemoteExamples.xcodeproj/project.pbxproj +++ b/TTRemoteExamples.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 539A1C4D101B50480085BC76 /* FlickrJSONResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 539A1C4A101B50480085BC76 /* FlickrJSONResponse.m */; }; 539A1C4E101B50480085BC76 /* FlickrSearchResultsModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 539A1C4C101B50480085BC76 /* FlickrSearchResultsModel.m */; }; 539A1D2B101B69550085BC76 /* FlickrXMLResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 539A1D2A101B69550085BC76 /* FlickrXMLResponse.m */; }; + 539A1DCB101BCAE30085BC76 /* SearchResultsModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 539A1DCA101BCAE30085BC76 /* SearchResultsModel.m */; }; 539C36E30FD6A99D00117201 /* GTMNSString+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 539C36E00FD6A99D00117201 /* GTMNSString+URLArguments.m */; }; 539C36E40FD6A99D00117201 /* GTMNSDictionary+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 539C36E20FD6A99D00117201 /* GTMNSDictionary+URLArguments.m */; }; 53CDB8D01018B56800AE0B64 /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CDB8CF1018B56800AE0B64 /* SearchResult.m */; }; @@ -110,9 +111,10 @@ 539A1C4A101B50480085BC76 /* FlickrJSONResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrJSONResponse.m; sourceTree = ""; }; 539A1C4B101B50480085BC76 /* FlickrSearchResultsModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlickrSearchResultsModel.h; sourceTree = ""; }; 539A1C4C101B50480085BC76 /* FlickrSearchResultsModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrSearchResultsModel.m; sourceTree = ""; }; - 539A1CB2101B5D540085BC76 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = App.h; sourceTree = ""; }; 539A1D29101B69550085BC76 /* FlickrXMLResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlickrXMLResponse.h; sourceTree = ""; }; 539A1D2A101B69550085BC76 /* FlickrXMLResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrXMLResponse.m; sourceTree = ""; }; + 539A1DC9101BC9A10085BC76 /* SearchResultsModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResultsModel.h; sourceTree = ""; }; + 539A1DCA101BCAE30085BC76 /* SearchResultsModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResultsModel.m; sourceTree = ""; }; 539C36DE0FD6A99D00117201 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; 539C36DF0FD6A99D00117201 /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSString+URLArguments.h"; sourceTree = ""; }; 539C36E00FD6A99D00117201 /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+URLArguments.m"; sourceTree = ""; }; @@ -157,7 +159,6 @@ 53D976520FFA57D600E62B9A /* Table Stuff */, 1D3623240D0F684500981E51 /* AppDelegate.h */, 1D3623250D0F684500981E51 /* AppDelegate.m */, - 539A1CB2101B5D540085BC76 /* App.h */, ); path = Classes; sourceTree = ""; @@ -330,6 +331,8 @@ 53CDB8CF1018B56800AE0B64 /* SearchResult.m */, 53F0E6440FD716AA00523DB2 /* URLModelResponse.h */, 53F0E6450FD716AA00523DB2 /* URLModelResponse.m */, + 539A1DC9101BC9A10085BC76 /* SearchResultsModel.h */, + 539A1DCA101BCAE30085BC76 /* SearchResultsModel.m */, ); name = Model; sourceTree = ""; @@ -444,6 +447,7 @@ 539A1C4D101B50480085BC76 /* FlickrJSONResponse.m in Sources */, 539A1C4E101B50480085BC76 /* FlickrSearchResultsModel.m in Sources */, 539A1D2B101B69550085BC76 /* FlickrXMLResponse.m in Sources */, + 539A1DCB101BCAE30085BC76 /* SearchResultsModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };