Skip to content

Commit

Permalink
Created the SearchResultsModel protocol and made YahooSearchResultsMo…
Browse files Browse the repository at this point in the history
…del and FlickrSearchResultsModel conform to this new protocol.

I also fixed a bug in YahooXMLResponse's XPath queries.
  • Loading branch information
klazuka committed Jul 25, 2009
1 parent 3314108 commit c2df82a
Show file tree
Hide file tree
Showing 14 changed files with 122 additions and 92 deletions.
31 changes: 0 additions & 31 deletions Classes/App.h

This file was deleted.

29 changes: 0 additions & 29 deletions Classes/AppDelegate.m
Expand Up @@ -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;
Expand Down
10 changes: 3 additions & 7 deletions Classes/FlickrSearchResultsModel.h
Expand Up @@ -6,7 +6,7 @@
//

#import "Three20/Three20.h"
#import "App.h"
#import "SearchResultsModel.h"

@class URLModelResponse;

Expand All @@ -17,17 +17,13 @@
* See the description of YahooSearchResultsModel.
*
*/
@interface FlickrSearchResultsModel : TTURLRequestModel
@interface FlickrSearchResultsModel : TTURLRequestModel <SearchResultsModel>
{
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
3 changes: 1 addition & 2 deletions Classes/FlickrSearchResultsModel.m
Expand Up @@ -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.

Expand Down Expand Up @@ -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",
Expand Down
16 changes: 10 additions & 6 deletions Classes/SearchPhotosViewController.m
Expand Up @@ -4,7 +4,7 @@

#import "SearchPhotosViewController.h"
#import "SearchResultsPhotoSource.h"
#import "App.h"
#import "SearchResultsModel.h"

@implementation SearchPhotosViewController

Expand All @@ -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<SearchResultsModel>)photoSource setSearchTerms:[queryField text]];

// Load the new data
[photoSource load:TTURLRequestCachePolicyDefault more:NO];

// Display the updated photoSource.
Expand Down
54 changes: 54 additions & 0 deletions 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 <TTModel>

@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<SearchResultsModel> CreateSearchModelWithCurrentSettings(void);
id<SearchResultsModel> CreateSearchModel(SearchService service, SearchResponseFormat responseFormat);

34 changes: 34 additions & 0 deletions 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<SearchResultsModel> CreateSearchModel(SearchService service, SearchResponseFormat responseFormat)
{
id<SearchResultsModel> 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<SearchResultsModel> CreateSearchModelWithCurrentSettings(void)
{
return CreateSearchModel(CurrentSearchService, CurrentSearchResponseFormat);
}
8 changes: 4 additions & 4 deletions Classes/SearchResultsPhotoSource.h
Expand Up @@ -7,7 +7,7 @@

#import "Three20/Three20.h"

@class YahooSearchResultsModel;
@protocol SearchResultsModel;

/*
* SearchResultsPhotoSource
Expand All @@ -28,15 +28,15 @@
*/
@interface SearchResultsPhotoSource : NSObject <TTPhotoSource>
{
YahooSearchResultsModel *model;
id<SearchResultsModel> *model;

// Backing storage for TTPhotoSource properties.
NSString *albumTitle;
int totalNumberOfPhotos;
}

- (id)initWithModel:(YahooSearchResultsModel *)theModel; // Designated initializer.
- (id)initWithModel:(id<SearchResultsModel>)theModel; // Designated initializer.

- (id<TTModel>)underlyingModel; // The model to which this PhotoSource forwards in order to conform to the TTModel protocol.
- (id<SearchResultsModel>)underlyingModel; // The model to which this PhotoSource forwards in order to conform to the TTModel protocol.

@end
3 changes: 2 additions & 1 deletion Classes/SearchResultsTableDataSource.m
Expand Up @@ -7,6 +7,7 @@

#import "SearchResultsTableDataSource.h"
#import "SearchResult.h"
#import "SearchResultsModel.h"

@implementation SearchResultsTableDataSource

Expand All @@ -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<SearchResultsModel>)self.model results])
[self.items addObject:[TTTableImageItem itemWithText:result.title
imageURL:result.thumbnailURL
defaultImage:[UIImage imageNamed:@"photo_placeholder.png"]
Expand Down
4 changes: 2 additions & 2 deletions Classes/SearchTableViewController.m
Expand Up @@ -4,7 +4,7 @@

#import "SearchTableViewController.h"
#import "SearchResultsTableDataSource.h"
#import "App.h"
#import "SearchResultsModel.h"

@implementation SearchTableViewController

Expand Down Expand Up @@ -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<SearchResultsModel>)self.model setSearchTerms:[searchBar text]];
[self reload];
[self.tableView scrollToTop:YES];
}
Expand Down
7 changes: 3 additions & 4 deletions Classes/YahooSearchResultsModel.h
Expand Up @@ -6,6 +6,7 @@
//

#import "Three20/Three20.h"
#import "SearchResultsModel.h"

@class URLModelResponse;

Expand Down Expand Up @@ -40,15 +41,13 @@
* directly into the YahooSearchResultsModel class.
*
*/
@interface YahooSearchResultsModel : TTURLRequestModel
@interface YahooSearchResultsModel : TTURLRequestModel <SearchResultsModel>
{
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
1 change: 0 additions & 1 deletion Classes/YahooSearchResultsModel.m
Expand Up @@ -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.

Expand Down
6 changes: 3 additions & 3 deletions Classes/YahooXMLResponse.m
Expand Up @@ -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],
Expand All @@ -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];
}

Expand Down
8 changes: 6 additions & 2 deletions TTRemoteExamples.xcodeproj/project.pbxproj
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -110,9 +111,10 @@
539A1C4A101B50480085BC76 /* FlickrJSONResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrJSONResponse.m; sourceTree = "<group>"; };
539A1C4B101B50480085BC76 /* FlickrSearchResultsModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlickrSearchResultsModel.h; sourceTree = "<group>"; };
539A1C4C101B50480085BC76 /* FlickrSearchResultsModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrSearchResultsModel.m; sourceTree = "<group>"; };
539A1CB2101B5D540085BC76 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = App.h; sourceTree = "<group>"; };
539A1D29101B69550085BC76 /* FlickrXMLResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlickrXMLResponse.h; sourceTree = "<group>"; };
539A1D2A101B69550085BC76 /* FlickrXMLResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlickrXMLResponse.m; sourceTree = "<group>"; };
539A1DC9101BC9A10085BC76 /* SearchResultsModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResultsModel.h; sourceTree = "<group>"; };
539A1DCA101BCAE30085BC76 /* SearchResultsModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResultsModel.m; sourceTree = "<group>"; };
539C36DE0FD6A99D00117201 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = "<group>"; };
539C36DF0FD6A99D00117201 /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSString+URLArguments.h"; sourceTree = "<group>"; };
539C36E00FD6A99D00117201 /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSString+URLArguments.m"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -157,7 +159,6 @@
53D976520FFA57D600E62B9A /* Table Stuff */,
1D3623240D0F684500981E51 /* AppDelegate.h */,
1D3623250D0F684500981E51 /* AppDelegate.m */,
539A1CB2101B5D540085BC76 /* App.h */,
);
path = Classes;
sourceTree = "<group>";
Expand Down Expand Up @@ -330,6 +331,8 @@
53CDB8CF1018B56800AE0B64 /* SearchResult.m */,
53F0E6440FD716AA00523DB2 /* URLModelResponse.h */,
53F0E6450FD716AA00523DB2 /* URLModelResponse.m */,
539A1DC9101BC9A10085BC76 /* SearchResultsModel.h */,
539A1DCA101BCAE30085BC76 /* SearchResultsModel.m */,
);
name = Model;
sourceTree = "<group>";
Expand Down Expand Up @@ -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;
};
Expand Down

0 comments on commit c2df82a

Please sign in to comment.