├── circle.yml ├── BestPractices ├── Modules │ ├── InjectorKeys.h │ ├── InjectorKeys.m │ ├── UIModule.h │ ├── NetworkModule.h │ ├── FoundationModule.h │ ├── InjectorProvider.h │ ├── FoundationModule.m │ ├── NetworkModule.m │ ├── InjectorProvider.m │ └── UIModule.m ├── AppDelegate.h ├── Network │ ├── RequestProvider.h │ ├── ArtistsService.h │ ├── HTTPClient.h │ ├── JSONClient.h │ ├── RequestProvider.m │ ├── JSONClient.m │ ├── HTTPClient.m │ └── ArtistsService.m ├── Controllers │ ├── ArtistViewController.h │ ├── ArtistsViewController.h │ ├── ArtistViewController.m │ └── ArtistsViewController.m ├── main.m ├── Presenters │ ├── ArtistCellPresenter.h │ ├── CellPresenter.h │ ├── ArtistCellPresenter.m │ ├── ArtistsPresenter.h │ ├── CellPresenterDataSource.h │ ├── CellPresenterDataSource.m │ └── ArtistsPresenter.m ├── Models │ ├── Artist.h │ └── Artist.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── AppDelegate.m ├── BestPractices-Info.plist └── Launch Screen.xib ├── BestPractices.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── BestPractices.xcscheme └── project.pbxproj ├── BestPracticesTests ├── Fixtures │ └── artists.json ├── Fakes │ ├── FakeCellPresenterDataSource.h │ └── FakeCellPresenterDataSource.m ├── Network │ ├── RequestProviderSpec.mm │ ├── JSONClientSpec.mm │ ├── HTTPClientSpec.mm │ └── ArtistsServiceSpec.mm ├── Presenters │ ├── ArtistCellPresenterSpec.mm │ ├── CellPresenterDataSourceSpec.mm │ └── ArtistsPresenterSpec.mm ├── Controllers │ ├── ArtistViewControllerSpec.mm │ └── ArtistsViewControllerSpec.mm ├── AppDelegateSpec.mm └── Info.plist ├── .gitmodules ├── .gitignore ├── README.md └── LICENSE /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | xcode: 3 | version: "7.0" 4 | checkout: 5 | post: 6 | - git submodule update --init 7 | -------------------------------------------------------------------------------- /BestPractices/Modules/InjectorKeys.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | extern NSString * const InjectorKeyRootViewController; 4 | -------------------------------------------------------------------------------- /BestPractices/Modules/InjectorKeys.m: -------------------------------------------------------------------------------- 1 | #import "InjectorKeys.h" 2 | 3 | NSString * const InjectorKeyRootViewController = @"InjectorKeyRootViewController"; 4 | -------------------------------------------------------------------------------- /BestPractices/Modules/UIModule.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "Blindside.h" 3 | 4 | 5 | @interface UIModule : NSObject 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /BestPractices/Modules/NetworkModule.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "Blindside.h" 3 | 4 | 5 | @interface NetworkModule : NSObject 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /BestPractices/Modules/FoundationModule.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "Blindside.h" 3 | 4 | 5 | @interface FoundationModule : NSObject 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /BestPractices/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /BestPractices/Network/RequestProvider.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface RequestProvider : NSObject 5 | 6 | - (NSURLRequest *)requestToGetArtists; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /BestPractices/Network/ArtistsService.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @class KSPromise; 5 | 6 | 7 | @interface ArtistsService : NSObject 8 | 9 | - (KSPromise *)getArtists; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices/Modules/InjectorProvider.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @protocol BSInjector; 5 | 6 | 7 | @interface InjectorProvider : NSObject 8 | 9 | + (id)injector; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices/Network/HTTPClient.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @class KSPromise; 5 | 6 | 7 | @interface HTTPClient : NSObject 8 | 9 | - (KSPromise *)sendRequest:(NSURLRequest *)request; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices/Network/JSONClient.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @class KSPromise; 5 | 6 | 7 | @interface JSONClient : NSObject 8 | 9 | - (KSPromise *)sendRequest:(NSURLRequest *)request; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices/Controllers/ArtistViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @class Artist; 5 | 6 | 7 | @interface ArtistViewController : UIViewController 8 | 9 | - (void)setupWithArtist:(Artist *)artist; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BestPractices/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppDelegate.h" 3 | 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /BestPracticesTests/Fixtures/artists.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "hugh-laurie", 4 | "name": "Hugh Laurie" 5 | }, 6 | { 7 | "id": "nightwish", 8 | "name": "Nightwish" 9 | }, 10 | { 11 | "id": "opeth", 12 | "name": "Opeth" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /BestPractices/Controllers/ArtistsViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "ArtistsPresenter.h" 3 | 4 | 5 | @interface ArtistsViewController : UIViewController 6 | 7 | @property (nonatomic, readonly) UITableView *tableView; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /BestPractices/Modules/FoundationModule.m: -------------------------------------------------------------------------------- 1 | #import "FoundationModule.h" 2 | 3 | 4 | @implementation FoundationModule 5 | 6 | - (void)configure:(id )binder { 7 | [binder bind:[NSOperationQueue class] toInstance:[NSOperationQueue mainQueue]]; 8 | } 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /BestPractices/Presenters/ArtistCellPresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CellPresenter.h" 3 | 4 | 5 | @class Artist; 6 | 7 | 8 | @interface ArtistCellPresenter : NSObject 9 | 10 | @property (nonatomic) Artist *artist; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /BestPractices/Presenters/CellPresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol CellPresenter 4 | 5 | + (void)registerInTableView:(UITableView *)tableView; 6 | 7 | - (void)presentInCell:(UITableViewCell *)cell; 8 | 9 | - (NSString *)cellIdentifier; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPracticesTests/Fakes/FakeCellPresenterDataSource.h: -------------------------------------------------------------------------------- 1 | #import "CellPresenterDataSource.h" 2 | 3 | 4 | @interface FakeCellPresenterDataSource : CellPresenterDataSource 5 | 6 | @property (nonatomic, readonly) NSArray *cellPresenters; 7 | @property (nonatomic, readonly) UITableView *tableView; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /BestPractices/Models/Artist.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface Artist : NSObject 5 | 6 | @property (nonatomic, copy, readonly) NSString *artistId; 7 | @property (nonatomic, copy, readonly) NSString *name; 8 | 9 | - (instancetype)initWithId:(NSString *)artistId name:(NSString *)name; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /BestPractices/Modules/NetworkModule.m: -------------------------------------------------------------------------------- 1 | #import "NetworkModule.h" 2 | #import "KSNetworkClient.h" 3 | #import "KSURLSessionClient.h" 4 | 5 | 6 | @implementation NetworkModule 7 | 8 | - (void)configure:(id )binder { 9 | [binder bind:@protocol(KSNetworkClient) toClass:[KSURLSessionClient class]]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /BestPractices/Network/RequestProvider.m: -------------------------------------------------------------------------------- 1 | #import "RequestProvider.h" 2 | 3 | 4 | @implementation RequestProvider 5 | 6 | - (NSURLRequest *)requestToGetArtists { 7 | NSURL *URL = [NSURL URLWithString:@"https://raw.githubusercontent.com/cbguder/BestPractices/master/BestPracticesSpecs/Fixtures/artists.json"]; 8 | return [NSURLRequest requestWithURL:URL]; 9 | } 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Externals/cedar"] 2 | path = Externals/cedar 3 | url = https://github.com/pivotal/cedar.git 4 | [submodule "Externals/blindside"] 5 | path = Externals/blindside 6 | url = https://github.com/jbsf/blindside.git 7 | [submodule "Externals/deferred"] 8 | path = Externals/deferred 9 | url = https://github.com/kseebaldt/deferred.git 10 | [submodule "Externals/PivotalCoreKit"] 11 | path = Externals/PivotalCoreKit 12 | url = https://github.com/pivotal/PivotalCoreKit.git 13 | -------------------------------------------------------------------------------- /BestPractices/Models/Artist.m: -------------------------------------------------------------------------------- 1 | #import "Artist.h" 2 | 3 | 4 | @interface Artist () 5 | 6 | @property (nonatomic, copy) NSString *artistId; 7 | @property (nonatomic, copy) NSString *name; 8 | 9 | @end 10 | 11 | 12 | @implementation Artist 13 | 14 | - (instancetype)initWithId:(NSString *)artistId name:(NSString *)name { 15 | self = [super init]; 16 | if (self) { 17 | self.artistId = artistId; 18 | self.name = name; 19 | } 20 | return self; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /BestPractices/Modules/InjectorProvider.m: -------------------------------------------------------------------------------- 1 | #import "InjectorProvider.h" 2 | #import "BSInjector.h" 3 | #import "FoundationModule.h" 4 | #import "NetworkModule.h" 5 | #import "UIModule.h" 6 | 7 | 8 | @implementation InjectorProvider 9 | 10 | + (id )injector { 11 | NSArray *modules = @[ 12 | [[FoundationModule alloc] init], 13 | [[NetworkModule alloc] init], 14 | [[UIModule alloc] init] 15 | ]; 16 | 17 | return [Blindside injectorWithModules:modules]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /BestPractices/Presenters/ArtistCellPresenter.m: -------------------------------------------------------------------------------- 1 | #import "ArtistCellPresenter.h" 2 | #import "Artist.h" 3 | 4 | 5 | @implementation ArtistCellPresenter 6 | 7 | + (void)registerInTableView:(UITableView *)tableView { 8 | return [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ArtistCell"]; 9 | } 10 | 11 | - (void)presentInCell:(UITableViewCell *)cell { 12 | cell.textLabel.text = self.artist.name; 13 | } 14 | 15 | - (NSString *)cellIdentifier { 16 | return @"ArtistCell"; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BestPractices/Presenters/ArtistsPresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CellPresenterDataSource.h" 3 | 4 | 5 | @class Artist; 6 | 7 | 8 | @protocol ArtistsPresenterDelegate 9 | 10 | - (void)artistsPresenterDidSelectArtist:(Artist *)artist; 11 | 12 | @end 13 | 14 | 15 | @interface ArtistsPresenter : NSObject 16 | 17 | @property (nonatomic, weak) id delegate; 18 | 19 | - (void)presentArtists:(NSArray *)artists inTableView:(UITableView *)tableView; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /BestPracticesTests/Fakes/FakeCellPresenterDataSource.m: -------------------------------------------------------------------------------- 1 | #import "FakeCellPresenterDataSource.h" 2 | 3 | 4 | @interface FakeCellPresenterDataSource () 5 | 6 | @property (nonatomic) NSArray *cellPresenters; 7 | @property (nonatomic) UITableView *tableView; 8 | 9 | @end 10 | 11 | 12 | @implementation FakeCellPresenterDataSource 13 | 14 | - (void)displayCellPresenters:(NSArray *)cellPresenters inTableView:(UITableView *)tableView { 15 | self.cellPresenters = cellPresenters; 16 | self.tableView = tableView; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BestPractices/Controllers/ArtistViewController.m: -------------------------------------------------------------------------------- 1 | #import "ArtistViewController.h" 2 | #import "Artist.h" 3 | 4 | 5 | @interface ArtistViewController () 6 | 7 | @property (nonatomic) Artist *artist; 8 | 9 | @end 10 | 11 | 12 | @implementation ArtistViewController 13 | 14 | - (void)setupWithArtist:(Artist *)artist { 15 | self.artist = artist; 16 | } 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | self.title = self.artist.name; 22 | 23 | self.view.backgroundColor = [UIColor whiteColor]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /BestPractices/Presenters/CellPresenterDataSource.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @protocol CellPresenter; 5 | 6 | 7 | @protocol CellPresenterDataSourceDelegate 8 | 9 | - (void)cellPresenterDataSourceDidSelectCellPresenter:(id)cellPresenter; 10 | 11 | @end 12 | 13 | 14 | @interface CellPresenterDataSource : NSObject 15 | 16 | @property (nonatomic, weak) id delegate; 17 | 18 | - (void)displayCellPresenters:(NSArray *)cellPresenters inTableView:(UITableView *)tableView; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /BestPractices/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /BestPracticesTests/Network/RequestProviderSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "RequestProvider.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | 6 | 7 | using namespace Cedar::Matchers; 8 | using namespace Cedar::Doubles; 9 | 10 | 11 | SPEC_BEGIN(RequestProviderSpec) 12 | 13 | describe(@"RequestProvider", ^{ 14 | __block RequestProvider *subject; 15 | __block id injector; 16 | 17 | beforeEach(^{ 18 | injector = (id)[InjectorProvider injector]; 19 | 20 | subject = [injector getInstance:[RequestProvider class]]; 21 | }); 22 | 23 | it(@"generates a request to get all artists", ^{ 24 | NSURLRequest *request = [subject requestToGetArtists]; 25 | 26 | request.URL should equal([NSURL URLWithString:@"https://raw.githubusercontent.com/cbguder/BestPractices/master/BestPracticesSpecs/Fixtures/artists.json"]); 27 | }); 28 | }); 29 | 30 | SPEC_END 31 | -------------------------------------------------------------------------------- /BestPractices/Modules/UIModule.m: -------------------------------------------------------------------------------- 1 | #import "UIModule.h" 2 | #import "InjectorKeys.h" 3 | #import "ArtistsViewController.h" 4 | 5 | 6 | @implementation UIModule 7 | 8 | - (void)configure:(id)binder { 9 | [binder bind:[UIScreen class] toBlock:^id(NSArray *args, id injector) { 10 | return [UIScreen mainScreen]; 11 | }]; 12 | 13 | [binder bind:[UIWindow class] toBlock:^id(NSArray *args, id injector) { 14 | UIScreen *screen = [injector getInstance:[UIScreen class]]; 15 | return [[UIWindow alloc] initWithFrame:screen.bounds]; 16 | }]; 17 | 18 | [binder bind:InjectorKeyRootViewController toBlock:^id(NSArray *args, id injector) { 19 | ArtistsViewController *artistsViewController = [injector getInstance:[ArtistsViewController class]]; 20 | return [[UINavigationController alloc] initWithRootViewController:artistsViewController]; 21 | }]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /BestPractices/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "InjectorProvider.h" 3 | #import "Blindside.h" 4 | #import "InjectorKeys.h" 5 | 6 | 7 | @interface AppDelegate () 8 | 9 | @property (nonatomic) id injector; 10 | 11 | @end 12 | 13 | 14 | @implementation AppDelegate 15 | 16 | - (instancetype)init { 17 | self = [super init]; 18 | if (self) { 19 | self.injector = [InjectorProvider injector]; 20 | } 21 | return self; 22 | } 23 | 24 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 25 | UIViewController *rootViewController = [self.injector getInstance:InjectorKeyRootViewController]; 26 | 27 | self.window = [self.injector getInstance:[UIWindow class]]; 28 | self.window.rootViewController = rootViewController; 29 | self.window.backgroundColor = [UIColor whiteColor]; 30 | [self.window makeKeyAndVisible]; 31 | 32 | return YES; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | #Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | -------------------------------------------------------------------------------- /BestPracticesTests/Presenters/ArtistCellPresenterSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "InjectorProvider.h" 3 | #import "Blindside.h" 4 | #import "ArtistCellPresenter.h" 5 | #import "Artist.h" 6 | 7 | 8 | using namespace Cedar::Matchers; 9 | using namespace Cedar::Doubles; 10 | 11 | 12 | SPEC_BEGIN(ArtistCellPresenterSpec) 13 | 14 | describe(@"ArtistCellPresenter", ^{ 15 | __block ArtistCellPresenter *subject; 16 | __block id injector; 17 | __block UITableViewCell *cell; 18 | 19 | beforeEach(^{ 20 | injector = (id)[InjectorProvider injector]; 21 | 22 | subject = [injector getInstance:[ArtistCellPresenter class]]; 23 | 24 | subject.artist = [[Artist alloc] initWithId:@"1" name:@"Pink Floyd"]; 25 | 26 | cell = [[UITableViewCell alloc] init]; 27 | [subject presentInCell:cell]; 28 | }); 29 | 30 | it(@"should display the artist name", ^{ 31 | cell.textLabel.text should equal(@"Pink Floyd"); 32 | }); 33 | }); 34 | 35 | SPEC_END 36 | -------------------------------------------------------------------------------- /BestPracticesTests/Controllers/ArtistViewControllerSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "ArtistViewController.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "Artist.h" 6 | 7 | 8 | using namespace Cedar::Matchers; 9 | using namespace Cedar::Doubles; 10 | 11 | 12 | SPEC_BEGIN(ArtistViewControllerSpec) 13 | 14 | describe(@"ArtistViewController", ^{ 15 | __block ArtistViewController *subject; 16 | __block id injector; 17 | __block Artist *artist; 18 | 19 | beforeEach(^{ 20 | injector = (id)[InjectorProvider injector]; 21 | 22 | artist = fake_for([Artist class]); 23 | artist stub_method(@selector(name)).and_return(@"My Special Artist"); 24 | 25 | subject = [injector getInstance:[ArtistViewController class]]; 26 | [subject setupWithArtist:artist]; 27 | subject.view should_not be_nil; 28 | }); 29 | 30 | it(@"should display the artist's name", ^{ 31 | subject.title should equal(@"My Special Artist"); 32 | }); 33 | }); 34 | 35 | SPEC_END 36 | -------------------------------------------------------------------------------- /BestPracticesTests/AppDelegateSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "AppDelegate.h" 3 | #import "ArtistsViewController.h" 4 | 5 | 6 | using namespace Cedar::Matchers; 7 | using namespace Cedar::Doubles; 8 | 9 | 10 | SPEC_BEGIN(AppDelegateSpec) 11 | 12 | describe(@"AppDelegate", ^{ 13 | __block AppDelegate *subject; 14 | 15 | beforeEach(^{ 16 | subject = [[AppDelegate alloc] init]; 17 | 18 | UIApplication *application = fake_for([UIApplication class]); 19 | 20 | [subject application:application didFinishLaunchingWithOptions:nil]; 21 | }); 22 | 23 | it(@"should set the root view controller", ^{ 24 | UINavigationController *navigationController = (id)subject.window.rootViewController; 25 | navigationController should be_instance_of([UINavigationController class]); 26 | navigationController.topViewController should be_instance_of([ArtistsViewController class]); 27 | }); 28 | 29 | it(@"should display the window", ^{ 30 | [subject.window isKeyWindow] should be_truthy; 31 | }); 32 | }); 33 | 34 | SPEC_END 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Best Practices 2 | 3 | A collection of things I consider to be best practices in test-driven iOS development 4 | 5 | [![CI Status](https://img.shields.io/circleci/project/cbguder/BestPractices/master.svg)](https://circleci.com/gh/cbguder/BestPractices/tree/master) 6 | 7 | ## Practices and Principles 8 | 9 | Some of the practices and principles I tried to demonstrate in this sample project are: 10 | 11 | * [Test-driven development][tdd] using [Cedar][] 12 | * [Dependency injection][di] using [Blindside][] 13 | * Promise-based async APIs using [KSDeferred][] 14 | * [Single responsibility principle][srp] 15 | * [Composition over inheritance][coi] 16 | * Stateless objects where possible 17 | 18 | [blindside]: https://github.com/jbsf/blindside 19 | [cedar]: https://github.com/pivotal/cedar 20 | [coi]: http://en.wikipedia.org/wiki/Composition_over_inheritance 21 | [di]: http://en.wikipedia.org/wiki/Dependency_injection 22 | [ksdeferred]: https://github.com/kseebaldt/deferred 23 | [srp]: http://en.wikipedia.org/wiki/Single_responsibility_principle 24 | [tdd]: http://en.wikipedia.org/wiki/Test-driven_development 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Can Berk Güder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /BestPracticesTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /BestPractices/Network/JSONClient.m: -------------------------------------------------------------------------------- 1 | #import "JSONClient.h" 2 | #import "Blindside.h" 3 | #import "HTTPClient.h" 4 | #import "KSDeferred.h" 5 | 6 | 7 | @interface JSONClient () 8 | 9 | @property(nonatomic) HTTPClient *httpClient; 10 | 11 | @end 12 | 13 | 14 | @implementation JSONClient 15 | 16 | + (BSInitializer *)bsInitializer { 17 | return [BSInitializer initializerWithClass:self 18 | selector:@selector(initWithHTTPClient:) 19 | argumentKeys:[HTTPClient class], nil]; 20 | } 21 | 22 | - (instancetype)initWithHTTPClient:(HTTPClient *)httpClient { 23 | self = [super init]; 24 | if (self) { 25 | self.httpClient = httpClient; 26 | } 27 | return self; 28 | } 29 | 30 | - (KSPromise *)sendRequest:(NSURLRequest *)request { 31 | KSPromise *httpPromise = [self.httpClient sendRequest:request]; 32 | 33 | KSPromise *promise = [httpPromise then:^id(NSData *data) { 34 | NSError *error = nil; 35 | 36 | id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 37 | 38 | if (error) { 39 | return error; 40 | } else { 41 | return jsonObject; 42 | } 43 | } error:^id(NSError *error) { 44 | return error; 45 | }]; 46 | 47 | return promise; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /BestPractices/BestPractices-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /BestPractices/Network/HTTPClient.m: -------------------------------------------------------------------------------- 1 | #import "HTTPClient.h" 2 | #import "KSPromise.h" 3 | #import "Blindside.h" 4 | #import "KSNetworkClient.h" 5 | 6 | 7 | @interface HTTPClient () 8 | 9 | @property(nonatomic) id networkClient; 10 | @property(nonatomic) NSOperationQueue *operationQueue; 11 | 12 | @end 13 | 14 | 15 | @implementation HTTPClient 16 | 17 | + (BSInitializer *)bsInitializer { 18 | return [BSInitializer initializerWithClass:self 19 | selector:@selector(initWithOperationQueue:networkClient:) 20 | argumentKeys: 21 | [NSOperationQueue class], 22 | @protocol(KSNetworkClient), 23 | nil]; 24 | } 25 | 26 | - (instancetype)initWithOperationQueue:(NSOperationQueue *)operationQueue 27 | networkClient:(id )networkClient { 28 | self = [super init]; 29 | if (self) { 30 | self.operationQueue = operationQueue; 31 | self.networkClient = networkClient; 32 | } 33 | return self; 34 | } 35 | 36 | - (KSPromise *)sendRequest:(NSURLRequest *)request { 37 | KSPromise *networkPromise = [self.networkClient sendAsynchronousRequest:request queue:self.operationQueue]; 38 | 39 | return [networkPromise then:^id(KSNetworkResponse *networkResponse) { 40 | return networkResponse.data; 41 | } error:^id(NSError *error) { 42 | return error; 43 | }]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /BestPractices/Presenters/CellPresenterDataSource.m: -------------------------------------------------------------------------------- 1 | #import "CellPresenterDataSource.h" 2 | #import "CellPresenter.h" 3 | 4 | 5 | @interface CellPresenterDataSource () 6 | 7 | @property (nonatomic, copy) NSArray *cellPresenters; 8 | 9 | @end 10 | 11 | 12 | @implementation CellPresenterDataSource 13 | 14 | - (void)displayCellPresenters:(NSArray *)cellPresenters inTableView:(UITableView *)tableView { 15 | self.cellPresenters = cellPresenters; 16 | 17 | tableView.dataSource = self; 18 | tableView.delegate = self; 19 | 20 | [tableView reloadData]; 21 | } 22 | 23 | #pragma mark - 24 | 25 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 26 | return self.cellPresenters.count; 27 | } 28 | 29 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 30 | id cellPresenter = self.cellPresenters[indexPath.row]; 31 | 32 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[cellPresenter cellIdentifier]]; 33 | 34 | [cellPresenter presentInCell:cell]; 35 | 36 | return cell; 37 | } 38 | 39 | #pragma mark - 40 | 41 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 42 | id cellPresenter = self.cellPresenters[indexPath.row]; 43 | [self.delegate cellPresenterDataSourceDidSelectCellPresenter:cellPresenter]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /BestPractices/Network/ArtistsService.m: -------------------------------------------------------------------------------- 1 | #import "ArtistsService.h" 2 | #import "Blindside.h" 3 | #import "KSDeferred.h" 4 | #import "Artist.h" 5 | #import "RequestProvider.h" 6 | #import "JSONClient.h" 7 | 8 | 9 | @interface ArtistsService () 10 | 11 | @property (nonatomic) RequestProvider *requestProvider; 12 | @property (nonatomic) JSONClient *jsonClient; 13 | 14 | @end 15 | 16 | 17 | @implementation ArtistsService 18 | 19 | + (BSInitializer *)bsInitializer { 20 | return [BSInitializer initializerWithClass:self 21 | selector:@selector(initWithRequestProvider:jsonClient:) 22 | argumentKeys: 23 | [RequestProvider class], 24 | [JSONClient class], 25 | nil]; 26 | } 27 | 28 | - (instancetype)initWithRequestProvider:(RequestProvider *)requestProvider 29 | jsonClient:(JSONClient *)jsonClient { 30 | self = [super init]; 31 | if (self) { 32 | self.requestProvider = requestProvider; 33 | self.jsonClient = jsonClient; 34 | } 35 | return self; 36 | } 37 | 38 | - (KSPromise *)getArtists { 39 | NSURLRequest *request = [self.requestProvider requestToGetArtists]; 40 | 41 | KSPromise *jsonPromise = [self.jsonClient sendRequest:request]; 42 | 43 | KSPromise *promise = [jsonPromise then:^id(NSArray *artistsJSON) { 44 | NSMutableArray *artists = [NSMutableArray arrayWithCapacity:artistsJSON.count]; 45 | 46 | for (NSDictionary *artistJSON in artistsJSON) { 47 | Artist *artist = [[Artist alloc] initWithId:artistJSON[@"id"] 48 | name:artistJSON[@"name"]]; 49 | 50 | [artists addObject:artist]; 51 | } 52 | 53 | return artists; 54 | } error:nil]; 55 | 56 | return promise; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BestPractices/Presenters/ArtistsPresenter.m: -------------------------------------------------------------------------------- 1 | #import "ArtistsPresenter.h" 2 | #import "Blindside.h" 3 | #import "Artist.h" 4 | #import "ArtistCellPresenter.h" 5 | 6 | 7 | @interface ArtistsPresenter () 8 | 9 | @property (nonatomic) CellPresenterDataSource *cellPresenterDataSource; 10 | 11 | @property (nonatomic, weak) id injector; 12 | 13 | @end 14 | 15 | 16 | @implementation ArtistsPresenter 17 | 18 | + (BSInitializer *)bsInitializer { 19 | return [BSInitializer initializerWithClass:self 20 | selector:@selector(initWithCellPresenterDataSource:) 21 | argumentKeys:[CellPresenterDataSource class], nil]; 22 | } 23 | 24 | - (instancetype)initWithCellPresenterDataSource:(CellPresenterDataSource *)cellPresenterDataSource { 25 | self = [super init]; 26 | if (self) { 27 | self.cellPresenterDataSource = cellPresenterDataSource; 28 | self.cellPresenterDataSource.delegate = self; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)presentArtists:(NSArray *)artists inTableView:(UITableView *)tableView { 34 | [ArtistCellPresenter registerInTableView:tableView]; 35 | 36 | NSMutableArray *cellPresenters = [NSMutableArray arrayWithCapacity:artists.count]; 37 | 38 | for (Artist *artist in artists) { 39 | ArtistCellPresenter *cellPresenter = [self.injector getInstance:[ArtistCellPresenter class]]; 40 | cellPresenter.artist = artist; 41 | [cellPresenters addObject:cellPresenter]; 42 | } 43 | 44 | [self.cellPresenterDataSource displayCellPresenters:cellPresenters inTableView:tableView]; 45 | } 46 | 47 | #pragma mark - 48 | 49 | - (void)cellPresenterDataSourceDidSelectCellPresenter:(ArtistCellPresenter *)artistCellPresenter { 50 | [self.delegate artistsPresenterDidSelectArtist:artistCellPresenter.artist]; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /BestPractices/Controllers/ArtistsViewController.m: -------------------------------------------------------------------------------- 1 | #import "ArtistsViewController.h" 2 | #import "Blindside.h" 3 | #import "ArtistsService.h" 4 | #import "KSPromise.h" 5 | #import "ArtistViewController.h" 6 | 7 | 8 | @interface ArtistsViewController () 9 | 10 | @property (nonatomic) ArtistsPresenter *artistsPresenter; 11 | @property (nonatomic) UITableView *tableView; 12 | @property (nonatomic) ArtistsService *artistsService; 13 | 14 | @property (nonatomic, weak) id injector; 15 | 16 | @end 17 | 18 | 19 | @implementation ArtistsViewController 20 | 21 | + (BSInitializer *)bsInitializer { 22 | return [BSInitializer initializerWithClass:self 23 | selector:@selector(initWithArtistsPresenter: 24 | artistsService:) 25 | argumentKeys: 26 | [ArtistsPresenter class], 27 | [ArtistsService class], 28 | nil]; 29 | } 30 | 31 | - (instancetype)initWithArtistsPresenter:(ArtistsPresenter *)artistsPresenter 32 | artistsService:(ArtistsService *)artistsService { 33 | self = [super init]; 34 | if (self) { 35 | self.artistsPresenter = artistsPresenter; 36 | self.artistsPresenter.delegate = self; 37 | self.artistsService = artistsService; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)viewDidLoad { 43 | [super viewDidLoad]; 44 | 45 | self.title = @"Artists"; 46 | 47 | self.tableView = [[UITableView alloc] init]; 48 | [self.view addSubview:self.tableView]; 49 | } 50 | 51 | - (void)viewWillAppear:(BOOL)animated { 52 | [super viewWillAppear:animated]; 53 | 54 | self.tableView.frame = self.view.bounds; 55 | 56 | KSPromise *promise = [self.artistsService getArtists]; 57 | [promise then:^id(NSArray *artists) { 58 | [self.artistsPresenter presentArtists:artists inTableView:self.tableView]; 59 | return nil; 60 | } error:nil]; 61 | } 62 | 63 | #pragma mark - 64 | 65 | - (void)artistsPresenterDidSelectArtist:(Artist *)artist { 66 | ArtistViewController *artistViewController = [self.injector getInstance:[ArtistViewController class]]; 67 | [artistViewController setupWithArtist:artist]; 68 | 69 | [self.navigationController pushViewController:artistViewController animated:YES]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /BestPracticesTests/Network/JSONClientSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "JSONClient.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "Blindside.h" 6 | #import "HTTPClient.h" 7 | #import "KSDeferred.h" 8 | 9 | using namespace Cedar::Matchers; 10 | using namespace Cedar::Doubles; 11 | 12 | SPEC_BEGIN(JSONClientSpec) 13 | 14 | describe(@"JSONClient", ^{ 15 | __block JSONClient *subject; 16 | __block id injector; 17 | __block HTTPClient *httpClient; 18 | 19 | beforeEach(^{ 20 | injector = (id)[InjectorProvider injector]; 21 | 22 | httpClient = fake_for([HTTPClient class]); 23 | [injector bind:[HTTPClient class] toInstance:httpClient]; 24 | 25 | subject = [injector getInstance:[JSONClient class]]; 26 | }); 27 | 28 | describe(@"sending a request", ^{ 29 | __block NSURLRequest *request; 30 | __block KSDeferred *httpDeferred; 31 | __block KSPromise *promise; 32 | 33 | beforeEach(^{ 34 | httpDeferred = [KSDeferred defer]; 35 | httpClient stub_method(@selector(sendRequest:)).and_return(httpDeferred.promise); 36 | 37 | request = fake_for([NSURLRequest class]); 38 | 39 | promise = [subject sendRequest:request]; 40 | }); 41 | 42 | it(@"makes a request to the correct url", ^{ 43 | httpClient should have_received(@selector(sendRequest:)).with(request); 44 | }); 45 | 46 | it(@"resolves the promise with the parsed JSON", ^{ 47 | NSString *jsonString = @"{\"foo\": [\"bar\"]}"; 48 | NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; 49 | 50 | [httpDeferred resolveWithValue:data]; 51 | 52 | NSDictionary *expectedJSON = @{ 53 | @"foo": @[@"bar"] 54 | }; 55 | 56 | promise.value should equal(expectedJSON); 57 | }); 58 | 59 | it(@"rejects the promise when loading fails", ^{ 60 | NSError *error = fake_for([NSError class]); 61 | 62 | [httpDeferred rejectWithError:error]; 63 | 64 | promise.error should be_same_instance_as(error); 65 | }); 66 | 67 | it(@"rejects the promise when JSON parsing fails", ^{ 68 | [httpDeferred resolveWithValue:[NSData data]]; 69 | 70 | promise.error should be_instance_of([NSError class]); 71 | }); 72 | }); 73 | }); 74 | 75 | SPEC_END 76 | -------------------------------------------------------------------------------- /BestPracticesTests/Network/HTTPClientSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "HTTPClient.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "Blindside.h" 6 | #import "KSNetworkClient.h" 7 | #import "KSDeferred.h" 8 | 9 | using namespace Cedar::Matchers; 10 | using namespace Cedar::Doubles; 11 | 12 | SPEC_BEGIN(HTTPClientSpec) 13 | 14 | describe(@"HTTPClient", ^{ 15 | __block HTTPClient *subject; 16 | __block id injector; 17 | __block id networkClient; 18 | __block NSOperationQueue *operationQueue; 19 | 20 | beforeEach(^{ 21 | injector = (id)[InjectorProvider injector]; 22 | 23 | networkClient = fake_for(@protocol(KSNetworkClient)); 24 | [injector bind:@protocol(KSNetworkClient) toInstance:networkClient]; 25 | 26 | operationQueue = fake_for([NSOperationQueue class]); 27 | [injector bind:[NSOperationQueue class] toInstance:operationQueue]; 28 | 29 | subject = [injector getInstance:[HTTPClient class]]; 30 | }); 31 | 32 | describe(@"sending a request", ^{ 33 | __block NSURLRequest *request; 34 | __block KSDeferred *networkDeferred; 35 | __block KSPromise *promise; 36 | 37 | beforeEach(^{ 38 | networkDeferred = [KSDeferred defer]; 39 | networkClient stub_method(@selector(sendAsynchronousRequest:queue:)).and_return(networkDeferred.promise); 40 | 41 | request = fake_for([NSURLRequest class]); 42 | 43 | promise = [subject sendRequest:request]; 44 | }); 45 | 46 | it(@"makes a request to the correct url", ^{ 47 | networkClient should have_received(@selector(sendAsynchronousRequest:queue:)) 48 | .with(request, operationQueue); 49 | }); 50 | 51 | it(@"resolves the promise with the returned data when the request succeeds", ^{ 52 | NSData *data = fake_for([NSData class]); 53 | 54 | KSNetworkResponse *networkResponse = fake_for([KSNetworkResponse class]); 55 | networkResponse stub_method(@selector(data)).and_return(data); 56 | 57 | [networkDeferred resolveWithValue:networkResponse]; 58 | 59 | promise.value should be_same_instance_as(data); 60 | }); 61 | 62 | it(@"rejects the promise when the request fails", ^{ 63 | NSError *error = fake_for([NSError class]); 64 | [networkDeferred rejectWithError:error]; 65 | 66 | promise.error should be_same_instance_as(error); 67 | }); 68 | }); 69 | }); 70 | 71 | SPEC_END 72 | -------------------------------------------------------------------------------- /BestPracticesTests/Network/ArtistsServiceSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "ArtistsService.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "RequestProvider.h" 6 | #import "JSONClient.h" 7 | #import "KSDeferred.h" 8 | #import "Artist.h" 9 | 10 | using namespace Cedar::Matchers; 11 | using namespace Cedar::Doubles; 12 | 13 | SPEC_BEGIN(ArtistsServiceSpec) 14 | 15 | describe(@"ArtistsService", ^{ 16 | __block ArtistsService *subject; 17 | __block id injector; 18 | __block RequestProvider *requestProvider; 19 | __block JSONClient *jsonClient; 20 | 21 | beforeEach(^{ 22 | injector = (id)[InjectorProvider injector]; 23 | 24 | requestProvider = fake_for([RequestProvider class]); 25 | [injector bind:[RequestProvider class] toInstance:requestProvider]; 26 | 27 | jsonClient = fake_for([JSONClient class]); 28 | [injector bind:[JSONClient class] toInstance:jsonClient]; 29 | 30 | subject = [injector getInstance:[ArtistsService class]]; 31 | }); 32 | 33 | describe(@"getting all artists", ^{ 34 | __block KSDeferred *jsonDeferred; 35 | __block NSURLRequest *request; 36 | __block KSPromise *promise; 37 | 38 | beforeEach(^{ 39 | request = fake_for([NSURLRequest class]); 40 | requestProvider stub_method(@selector(requestToGetArtists)).and_return(request); 41 | 42 | jsonDeferred = [KSDeferred defer]; 43 | jsonClient stub_method(@selector(sendRequest:)).and_return(jsonDeferred.promise); 44 | 45 | promise = [subject getArtists]; 46 | }); 47 | 48 | it(@"makes a request", ^{ 49 | jsonClient should have_received(@selector(sendRequest:)).with(request); 50 | }); 51 | 52 | it(@"resolves the promise with an array of artists when the request succeeds", ^{ 53 | NSString *fixturePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"artists" ofType:@"json"]; 54 | NSData *fixtureData = [NSData dataWithContentsOfFile:fixturePath]; 55 | NSArray *jsonArtists = [NSJSONSerialization JSONObjectWithData:fixtureData options:0 error:nil]; 56 | [jsonDeferred resolveWithValue:jsonArtists]; 57 | 58 | NSArray *artists = promise.value; 59 | artists.count should equal(3); 60 | 61 | Artist *artist1 = artists[0]; 62 | artist1.artistId should equal(@"hugh-laurie"); 63 | artist1.name should equal(@"Hugh Laurie"); 64 | 65 | Artist *artist2 = artists[1]; 66 | artist2.artistId should equal(@"nightwish"); 67 | artist2.name should equal(@"Nightwish"); 68 | 69 | Artist *artist3 = artists[2]; 70 | artist3.artistId should equal(@"opeth"); 71 | artist3.name should equal(@"Opeth"); 72 | }); 73 | 74 | it(@"rejects the promise with an error when the request fails", ^{ 75 | NSError *error = fake_for([NSError class]); 76 | [jsonDeferred rejectWithError:error]; 77 | 78 | promise.error should be_same_instance_as(error); 79 | }); 80 | }); 81 | }); 82 | 83 | SPEC_END 84 | -------------------------------------------------------------------------------- /BestPracticesTests/Presenters/CellPresenterDataSourceSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "InjectorProvider.h" 3 | #import "Blindside.h" 4 | #import "CellPresenterDataSource.h" 5 | #import "CellPresenter.h" 6 | 7 | 8 | using namespace Cedar::Matchers; 9 | using namespace Cedar::Doubles; 10 | 11 | 12 | SPEC_BEGIN(CellPresenterDataSourceSpec) 13 | 14 | describe(@"CellPresenterDataSource", ^{ 15 | __block CellPresenterDataSource *subject; 16 | __block id injector; 17 | 18 | beforeEach(^{ 19 | injector = (id)[InjectorProvider injector]; 20 | 21 | subject = [injector getInstance:[CellPresenterDataSource class]]; 22 | subject.delegate = nice_fake_for(@protocol(CellPresenterDataSourceDelegate)); 23 | }); 24 | 25 | describe(@"displaying cell presenters in a table view", ^{ 26 | __block UITableView *tableView; 27 | __block NSArray *cellPresenters; 28 | 29 | id (^createCellPresenter)() = ^id { 30 | id cellPresenter = nice_fake_for(@protocol(CellPresenter)); 31 | cellPresenter stub_method(@selector(cellIdentifier)).and_return(@"My Cell Identifier"); 32 | return cellPresenter; 33 | }; 34 | 35 | beforeEach(^{ 36 | tableView = nice_fake_for([UITableView class]); 37 | 38 | cellPresenters = @[ 39 | createCellPresenter(), 40 | createCellPresenter(), 41 | createCellPresenter() 42 | ]; 43 | 44 | [subject displayCellPresenters:cellPresenters inTableView:tableView]; 45 | }); 46 | 47 | it(@"should set itself as the data source and delegate on the table view", ^{ 48 | tableView should have_received(@selector(setDataSource:)).with(subject); 49 | tableView should have_received(@selector(setDelegate:)).with(subject); 50 | }); 51 | 52 | it(@"should reload the table view", ^{ 53 | tableView should have_received(@selector(reloadData)); 54 | }); 55 | 56 | it(@"should return the correct number of rows", ^{ 57 | [subject tableView:tableView numberOfRowsInSection:0] should equal(3); 58 | }); 59 | 60 | it(@"should use the cell presenters to configure the cells", ^{ 61 | UITableViewCell *tableViewCell = fake_for([UITableViewCell class]); 62 | 63 | tableView stub_method(@selector(dequeueReusableCellWithIdentifier:)).with(@"My Cell Identifier").and_return(tableViewCell); 64 | 65 | UITableViewCell *cell = [subject tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]; 66 | 67 | cellPresenters[2] should have_received(@selector(presentInCell:)).with(cell); 68 | cell should be_same_instance_as(tableViewCell); 69 | }); 70 | 71 | it(@"should inform its delegate when a cell is tapped", ^{ 72 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0]; 73 | [subject tableView:tableView didSelectRowAtIndexPath:indexPath]; 74 | 75 | subject.delegate should have_received(@selector(cellPresenterDataSourceDidSelectCellPresenter:)).with(cellPresenters[1]); 76 | }); 77 | }); 78 | }); 79 | 80 | SPEC_END 81 | -------------------------------------------------------------------------------- /BestPracticesTests/Controllers/ArtistsViewControllerSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "ArtistsViewController.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "ArtistsService.h" 6 | #import "KSDeferred.h" 7 | #import "Artist.h" 8 | #import "ArtistViewController.h" 9 | 10 | 11 | using namespace Cedar::Matchers; 12 | using namespace Cedar::Doubles; 13 | 14 | 15 | SPEC_BEGIN(ArtistsViewControllerSpec) 16 | 17 | describe(@"ArtistsViewController", ^{ 18 | __block ArtistsViewController *subject; 19 | __block id injector; 20 | __block ArtistsPresenter *artistsPresenter; 21 | __block ArtistsService *artistsService; 22 | 23 | void (^makeViewAppear)() = ^{ 24 | [subject viewWillAppear:NO]; 25 | [subject viewDidAppear:NO]; 26 | }; 27 | 28 | beforeEach(^{ 29 | injector = (id)[InjectorProvider injector]; 30 | 31 | artistsPresenter = nice_fake_for([ArtistsPresenter class]); 32 | [injector bind:[ArtistsPresenter class] toInstance:artistsPresenter]; 33 | 34 | artistsService = nice_fake_for([ArtistsService class]); 35 | [injector bind:[ArtistsService class] toInstance:artistsService]; 36 | 37 | subject = [injector getInstance:[ArtistsViewController class]]; 38 | subject.view should_not be_nil; 39 | }); 40 | 41 | describe(@"displaying artists", ^{ 42 | __block KSDeferred *deferred; 43 | 44 | beforeEach(^{ 45 | deferred = [KSDeferred defer]; 46 | 47 | artistsService stub_method(@selector(getArtists)).and_return(deferred.promise); 48 | 49 | makeViewAppear(); 50 | }); 51 | 52 | it(@"should display the artists in the table view when they are fetched successfully", ^{ 53 | NSArray *artists = fake_for([NSArray class]); 54 | 55 | [deferred resolveWithValue:artists]; 56 | 57 | artistsPresenter should have_received(@selector(presentArtists:inTableView:)).with(artists, subject.tableView); 58 | }); 59 | }); 60 | 61 | describe(@"as an artists presenter delegate", ^{ 62 | __block UINavigationController *navigationController; 63 | __block ArtistViewController *artistViewController; 64 | 65 | beforeEach(^{ 66 | artistViewController = [injector getInstance:[ArtistViewController class]]; 67 | spy_on(artistViewController); 68 | [injector bind:[ArtistViewController class] toInstance:artistViewController]; 69 | 70 | navigationController = [[UINavigationController alloc] initWithRootViewController:subject]; 71 | }); 72 | 73 | it(@"should set itself as the artists presenter's delegate", ^{ 74 | artistsPresenter should have_received(@selector(setDelegate:)).with(subject); 75 | }); 76 | 77 | it(@"should display an artist's details when the user selects an artist", ^{ 78 | Artist *artist = nice_fake_for([Artist class]); 79 | 80 | [subject artistsPresenterDidSelectArtist:artist]; 81 | 82 | navigationController.topViewController should be_same_instance_as(artistViewController); 83 | artistViewController should have_received(@selector(setupWithArtist:)).with(artist); 84 | }); 85 | }); 86 | }); 87 | 88 | SPEC_END 89 | -------------------------------------------------------------------------------- /BestPracticesTests/Presenters/ArtistsPresenterSpec.mm: -------------------------------------------------------------------------------- 1 | #import "Cedar.h" 2 | #import "ArtistsPresenter.h" 3 | #import "InjectorProvider.h" 4 | #import "Blindside.h" 5 | #import "FakeCellPresenterDataSource.h" 6 | #import "Artist.h" 7 | #import "ArtistCellPresenter.h" 8 | 9 | 10 | using namespace Cedar::Matchers; 11 | using namespace Cedar::Doubles; 12 | 13 | 14 | SPEC_BEGIN(ArtistsPresenterSpec) 15 | 16 | describe(@"ArtistsPresenter", ^{ 17 | __block ArtistsPresenter *subject; 18 | __block id injector; 19 | __block FakeCellPresenterDataSource *cellPresenterDataSource; 20 | __block UITableView *tableView; 21 | 22 | beforeEach(^{ 23 | injector = (id)[InjectorProvider injector]; 24 | 25 | cellPresenterDataSource = [[FakeCellPresenterDataSource alloc] init]; 26 | [injector bind:[CellPresenterDataSource class] toInstance:cellPresenterDataSource]; 27 | 28 | tableView = [[UITableView alloc] init]; 29 | 30 | subject = [injector getInstance:[ArtistsPresenter class]]; 31 | subject.delegate = nice_fake_for(@protocol(ArtistsPresenterDelegate)); 32 | }); 33 | 34 | it(@"should generate artist cell presenters and hand them over to the cell presenter data source", ^{ 35 | NSArray *artists = @[ 36 | fake_for([Artist class]), 37 | fake_for([Artist class]), 38 | fake_for([Artist class]) 39 | ]; 40 | 41 | [subject presentArtists:artists inTableView:tableView]; 42 | 43 | cellPresenterDataSource.tableView should be_same_instance_as(tableView); 44 | 45 | cellPresenterDataSource.cellPresenters.count should equal(3); 46 | 47 | for (int i = 0; i < 3; i++) { 48 | ArtistCellPresenter *cellPresenter = cellPresenterDataSource.cellPresenters[i]; 49 | cellPresenter should be_instance_of([ArtistCellPresenter class]); 50 | cellPresenter.artist should be_same_instance_as(artists[i]); 51 | } 52 | }); 53 | 54 | it(@"should register the cell types on the table view", ^{ 55 | NSArray *artists = @[fake_for([Artist class])]; 56 | 57 | [subject presentArtists:artists inTableView:tableView]; 58 | 59 | ArtistCellPresenter *cellPresenter = cellPresenterDataSource.cellPresenters.firstObject; 60 | 61 | [tableView dequeueReusableCellWithIdentifier:cellPresenter.cellIdentifier] should_not be_nil; 62 | }); 63 | 64 | describe(@"as a cell presenter data source's delegate", ^{ 65 | it(@"should set itself as the cell presenter data source's delegate", ^{ 66 | cellPresenterDataSource.delegate should be_same_instance_as(subject); 67 | }); 68 | 69 | it(@"should inform its delegate when the user taps on a cell", ^{ 70 | NSArray *artists = @[ 71 | fake_for([Artist class]), 72 | fake_for([Artist class]), 73 | fake_for([Artist class]) 74 | ]; 75 | 76 | [subject presentArtists:artists inTableView:tableView]; 77 | 78 | ArtistCellPresenter *cellPresenter = cellPresenterDataSource.cellPresenters[1]; 79 | [subject cellPresenterDataSourceDidSelectCellPresenter:cellPresenter]; 80 | 81 | subject.delegate should have_received(@selector(artistsPresenterDidSelectArtist:)).with(artists[1]); 82 | }); 83 | }); 84 | }); 85 | 86 | SPEC_END 87 | -------------------------------------------------------------------------------- /BestPractices/Launch Screen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /BestPractices.xcodeproj/xcshareddata/xcschemes/BestPractices.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /BestPractices.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2225F7DA142A2DA92BDB35F5 /* JSONClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225F8BA27105B8EC773EE8D /* JSONClient.m */; }; 11 | 2225F8685C87791451F87892 /* HTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225F31DE7A12821D08FB6D8 /* HTTPClient.m */; }; 12 | 2225FB3AEBA39757263BC8A9 /* NetworkModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225FDE9BB696E631352A547 /* NetworkModule.m */; }; 13 | 2225FC41AAD3AC205BA2B147 /* ArtistViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225F182E9479D9347EBA74A /* ArtistViewController.m */; }; 14 | 2225FD911CE7FDBA49E61750 /* FoundationModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225F7D69CE3204D81E2C21A /* FoundationModule.m */; }; 15 | 2225FE5BED01473F71B63378 /* InjectorProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 2225F92CBED5E79032067389 /* InjectorProvider.m */; }; 16 | 4C0B92FF1ACF5D7100DE75AC /* Launch Screen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0B92FE1ACF5D7100DE75AC /* Launch Screen.xib */; }; 17 | 4C1650CD18E50CA1000336FD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C1650CC18E50CA1000336FD /* Foundation.framework */; }; 18 | 4C1650CF18E50CA1000336FD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C1650CE18E50CA1000336FD /* CoreGraphics.framework */; }; 19 | 4C1650D118E50CA1000336FD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C1650D018E50CA1000336FD /* UIKit.framework */; }; 20 | 4C1650D918E50CA1000336FD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1650D818E50CA1000336FD /* main.m */; }; 21 | 4C1650DD18E50CA1000336FD /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1650DC18E50CA1000336FD /* AppDelegate.m */; }; 22 | 4C1650DF18E50CA1000336FD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C1650DE18E50CA1000336FD /* Images.xcassets */; }; 23 | 4C18B1B61BC4E2E300CF54F4 /* AppDelegateSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C8145A718E5133900FA565A /* AppDelegateSpec.mm */; }; 24 | 4C18B1B71BC4E2E700CF54F4 /* ArtistsViewControllerSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C8145C818E5194900FA565A /* ArtistsViewControllerSpec.mm */; }; 25 | 4C18B1B81BC4E2EA00CF54F4 /* ArtistViewControllerSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2225F3025C16CE3BBA32DDE9 /* ArtistViewControllerSpec.mm */; }; 26 | 4C18B1B91BC4E2EF00CF54F4 /* FakeCellPresenterDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = AE0D930018EF6CB30043F06A /* FakeCellPresenterDataSource.m */; }; 27 | 4C18B1BA1BC4E2F300CF54F4 /* ArtistCellPresenterSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE0D92EB18EF5BE40043F06A /* ArtistCellPresenterSpec.mm */; }; 28 | 4C18B1BB1BC4E2F600CF54F4 /* ArtistsPresenterSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE0D92FC18EF6B2F0043F06A /* ArtistsPresenterSpec.mm */; }; 29 | 4C18B1BC1BC4E2F900CF54F4 /* CellPresenterDataSourceSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3C88218E78E070082556D /* CellPresenterDataSourceSpec.mm */; }; 30 | 4C18B1BE1BC4E30800CF54F4 /* ArtistsServiceSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4CBB0C3F1AD0715F00F03491 /* ArtistsServiceSpec.mm */; }; 31 | 4C18B1BF1BC4E30800CF54F4 /* HTTPClientSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2225F6CA33682145B828BC8D /* HTTPClientSpec.mm */; }; 32 | 4C18B1C01BC4E30800CF54F4 /* JSONClientSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2225FF83F6A1F3603EF1DE61 /* JSONClientSpec.mm */; }; 33 | 4C18B1C11BC4E30800CF54F4 /* RequestProviderSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2225FBFF7DE7C89C66D1FA71 /* RequestProviderSpec.mm */; }; 34 | 4C18B1C21BC4E31000CF54F4 /* artists.json in Resources */ = {isa = PBXBuildFile; fileRef = 2225F5A602D89DA85B78DBD2 /* artists.json */; }; 35 | 4C18B1C51BC4E3D200CF54F4 /* libCedar.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C833A9F18E50DD30011D3C3 /* libCedar.a */; }; 36 | 4C18B1CA1BC4E43900CF54F4 /* libUIKit+PivotalSpecHelper-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C04CE051AF868DE005DA4D6 /* libUIKit+PivotalSpecHelper-StaticLib.a */; }; 37 | 4C18B1CB1BC4E43C00CF54F4 /* libUIKit+PivotalSpecHelperStubs-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C04CE071AF868DE005DA4D6 /* libUIKit+PivotalSpecHelperStubs-StaticLib.a */; }; 38 | 4C8145BC18E5169700FA565A /* ArtistsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8145B818E5169700FA565A /* ArtistsViewController.m */; }; 39 | 4C8145BE18E5169700FA565A /* UIModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8145BB18E5169700FA565A /* UIModule.m */; }; 40 | 4C8145C218E5173700FA565A /* InjectorKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8145C118E5173700FA565A /* InjectorKeys.m */; }; 41 | 4CA3C85B18E77B3B0082556D /* CellPresenterDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3C85A18E77B3B0082556D /* CellPresenterDataSource.m */; }; 42 | 4CA3C85F18E77BB70082556D /* ArtistsPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3C85E18E77BB70082556D /* ArtistsPresenter.m */; }; 43 | 4CA3C86418E77C840082556D /* ArtistsService.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3C86318E77C840082556D /* ArtistsService.m */; }; 44 | 4CA4827118E5100B00E524B6 /* libBlindside-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CA4826E18E50FF800E524B6 /* libBlindside-StaticLib.a */; }; 45 | 4CA4828418E5107C00E524B6 /* libDeferred.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CA4827D18E5106800E524B6 /* libDeferred.a */; }; 46 | 4CAA2CF018E79C9B00488E9B /* Artist.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAA2CEF18E79C9B00488E9B /* Artist.m */; }; 47 | 4CAA2CF418E79CEA00488E9B /* ArtistCellPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAA2CF318E79CEA00488E9B /* ArtistCellPresenter.m */; }; 48 | 4CAB2EA71ACF600B002AB81E /* RequestProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB2EA61ACF600B002AB81E /* RequestProvider.m */; }; 49 | /* End PBXBuildFile section */ 50 | 51 | /* Begin PBXContainerItemProxy section */ 52 | 4C04CE021AF868DE005DA4D6 /* PBXContainerItemProxy */ = { 53 | isa = PBXContainerItemProxy; 54 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 55 | proxyType = 2; 56 | remoteGlobalIDString = AEBCCC24168B999F0056EE83; 57 | remoteInfo = "UIKit+PivotalCore-StaticLib"; 58 | }; 59 | 4C04CE041AF868DE005DA4D6 /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 62 | proxyType = 2; 63 | remoteGlobalIDString = AEBCCC64168B9AF10056EE83; 64 | remoteInfo = "UIKit+PivotalSpecHelper-StaticLib"; 65 | }; 66 | 4C04CE061AF868DE005DA4D6 /* PBXContainerItemProxy */ = { 67 | isa = PBXContainerItemProxy; 68 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 69 | proxyType = 2; 70 | remoteGlobalIDString = AEC40C89174C203700474D2D; 71 | remoteInfo = "UIKit+PivotalSpecHelperStubs-StaticLib"; 72 | }; 73 | 4C04CE081AF868DE005DA4D6 /* PBXContainerItemProxy */ = { 74 | isa = PBXContainerItemProxy; 75 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 76 | proxyType = 2; 77 | remoteGlobalIDString = AEBCCC34168B99ED0056EE83; 78 | remoteInfo = "UIKit-StaticLibSpec"; 79 | }; 80 | 4C04CE0A1AF868DE005DA4D6 /* PBXContainerItemProxy */ = { 81 | isa = PBXContainerItemProxy; 82 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 83 | proxyType = 2; 84 | remoteGlobalIDString = AE118AA218D6B57000C90D6B; 85 | remoteInfo = "UIKit-StaticLibSpecBundle"; 86 | }; 87 | 4C0B92EA1ACF598000DE75AC /* PBXContainerItemProxy */ = { 88 | isa = PBXContainerItemProxy; 89 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 90 | proxyType = 2; 91 | remoteGlobalIDString = AE248F9819DCD52500092C14; 92 | remoteInfo = "Cedar OS X Host App"; 93 | }; 94 | 4C0B92EC1ACF598000DE75AC /* PBXContainerItemProxy */ = { 95 | isa = PBXContainerItemProxy; 96 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 97 | proxyType = 2; 98 | remoteGlobalIDString = AE248FAA19DCD52500092C14; 99 | remoteInfo = "Cedar OS X Host AppTests"; 100 | }; 101 | 4C0B92F31ACF598000DE75AC /* PBXContainerItemProxy */ = { 102 | isa = PBXContainerItemProxy; 103 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 104 | proxyType = 2; 105 | remoteGlobalIDString = AE68319B1A365DC600B1B815; 106 | remoteInfo = DeferredSpecs; 107 | }; 108 | 4C0B92F51ACF598000DE75AC /* PBXContainerItemProxy */ = { 109 | isa = PBXContainerItemProxy; 110 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 111 | proxyType = 2; 112 | remoteGlobalIDString = AE68316C1A365CF600B1B815; 113 | remoteInfo = "Deferred-OSXSpecs"; 114 | }; 115 | 4C0C9D921C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 116 | isa = PBXContainerItemProxy; 117 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 118 | proxyType = 2; 119 | remoteGlobalIDString = 343267161BAA2A9C005F2D7A; 120 | remoteInfo = "Blindside-tvOS"; 121 | }; 122 | 4C0C9D941C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 123 | isa = PBXContainerItemProxy; 124 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 125 | proxyType = 2; 126 | remoteGlobalIDString = 344DA5171BAB042E004270AD; 127 | remoteInfo = "Blindside-tvOS BuildTest"; 128 | }; 129 | 4C0C9DA81C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 130 | isa = PBXContainerItemProxy; 131 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 132 | proxyType = 2; 133 | remoteGlobalIDString = 346261DF1B995239002CAEBD; 134 | remoteInfo = "Cedar-watchOS"; 135 | }; 136 | 4C0C9DAA1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 137 | isa = PBXContainerItemProxy; 138 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 139 | proxyType = 2; 140 | remoteGlobalIDString = 34D7C3CA1BB9747400E8E523; 141 | remoteInfo = "Cedar-tvOS"; 142 | }; 143 | 4C0C9DAC1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 144 | isa = PBXContainerItemProxy; 145 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 146 | proxyType = 2; 147 | remoteGlobalIDString = 34852D211BBE35FF0072D249; 148 | remoteInfo = "Cedar-watchOS HostApp"; 149 | }; 150 | 4C0C9DAE1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 151 | isa = PBXContainerItemProxy; 152 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 153 | proxyType = 2; 154 | remoteGlobalIDString = 346262781B99C1DB002CAEBD; 155 | remoteInfo = "Cedar-watchOS Specs"; 156 | }; 157 | 4C0C9DB01C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 158 | isa = PBXContainerItemProxy; 159 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 160 | proxyType = 2; 161 | remoteGlobalIDString = 346262841B99C1DC002CAEBD; 162 | remoteInfo = "Cedar-watchOS Specs Extension"; 163 | }; 164 | 4C0C9DB21C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 165 | isa = PBXContainerItemProxy; 166 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 167 | proxyType = 2; 168 | remoteGlobalIDString = 34D7C4691BB9B71600E8E523; 169 | remoteInfo = "Cedar-tvOS SpecBundle"; 170 | }; 171 | 4C0C9DBE1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 172 | isa = PBXContainerItemProxy; 173 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 174 | proxyType = 2; 175 | remoteGlobalIDString = 34490E751BC7F7D50067BFD5; 176 | remoteInfo = "Deferred-watchOS"; 177 | }; 178 | 4C0C9DC01C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 179 | isa = PBXContainerItemProxy; 180 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 181 | proxyType = 2; 182 | remoteGlobalIDString = 34490E541BC7F4EB0067BFD5; 183 | remoteInfo = "Deferred-tvOS"; 184 | }; 185 | 4C0C9DC21C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 186 | isa = PBXContainerItemProxy; 187 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 188 | proxyType = 2; 189 | remoteGlobalIDString = 34490EA01BC828B90067BFD5; 190 | remoteInfo = "Deferred-watchOS-Framework"; 191 | }; 192 | 4C0C9DC41C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 193 | isa = PBXContainerItemProxy; 194 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 195 | proxyType = 2; 196 | remoteGlobalIDString = 34490E931BC8255D0067BFD5; 197 | remoteInfo = "Deferred-tvOS-Framework"; 198 | }; 199 | 4C0C9DC61C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 200 | isa = PBXContainerItemProxy; 201 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 202 | proxyType = 2; 203 | remoteGlobalIDString = 34490ECA1BC82E920067BFD5; 204 | remoteInfo = "Deferred-tvOSSpecs"; 205 | }; 206 | 4C0C9DD71C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 207 | isa = PBXContainerItemProxy; 208 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 209 | proxyType = 2; 210 | remoteGlobalIDString = AE3F05A11BE81FDD002BA0DE; 211 | remoteInfo = "UIKit+PivotalCore-iOS"; 212 | }; 213 | 4C0C9DD91C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 214 | isa = PBXContainerItemProxy; 215 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 216 | proxyType = 2; 217 | remoteGlobalIDString = 34A6645D1BDFE6AD00EF0FEA; 218 | remoteInfo = "UIKit+PivotalCore-tvOS"; 219 | }; 220 | 4C0C9DDB1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 221 | isa = PBXContainerItemProxy; 222 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 223 | proxyType = 2; 224 | remoteGlobalIDString = AE0D6A711BE941290095ACF3; 225 | remoteInfo = "UIKit+PivotalSpecHelper-iOS"; 226 | }; 227 | 4C0C9DDD1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 228 | isa = PBXContainerItemProxy; 229 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 230 | proxyType = 2; 231 | remoteGlobalIDString = 34A6646A1BDFE6D400EF0FEA; 232 | remoteInfo = "UIKit+PivotalSpecHelper-tvOS"; 233 | }; 234 | 4C0C9DDF1C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 235 | isa = PBXContainerItemProxy; 236 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 237 | proxyType = 2; 238 | remoteGlobalIDString = AE0D6A991BE942490095ACF3; 239 | remoteInfo = "UIKit+PivotalSpecHelperStubs-iOS"; 240 | }; 241 | 4C0C9DE11C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 242 | isa = PBXContainerItemProxy; 243 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 244 | proxyType = 2; 245 | remoteGlobalIDString = 34A664771BDFE6E500EF0FEA; 246 | remoteInfo = "UIKit+PivotalSpecHelperStubs-tvOS"; 247 | }; 248 | 4C0C9DE31C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 249 | isa = PBXContainerItemProxy; 250 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 251 | proxyType = 2; 252 | remoteGlobalIDString = 346B40E11BE06F4E002A390E; 253 | remoteInfo = "UIKit-tvOS SpecHost"; 254 | }; 255 | 4C0C9DE51C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 256 | isa = PBXContainerItemProxy; 257 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 258 | proxyType = 2; 259 | remoteGlobalIDString = 34A664CD1BE027B500EF0FEA; 260 | remoteInfo = "UIKit-tvOS SpecBundle"; 261 | }; 262 | 4C0C9DE71C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 263 | isa = PBXContainerItemProxy; 264 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 265 | proxyType = 2; 266 | remoteGlobalIDString = AE0D6A451BE93CAD0095ACF3; 267 | remoteInfo = "UIKit-iOS SpecHost"; 268 | }; 269 | 4C0C9DE91C4F68B4006DA0BF /* PBXContainerItemProxy */ = { 270 | isa = PBXContainerItemProxy; 271 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 272 | proxyType = 2; 273 | remoteGlobalIDString = AE3F05AA1BE81FDD002BA0DE; 274 | remoteInfo = "UIKit-iOS SpecBundle"; 275 | }; 276 | 4C18B1921BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 277 | isa = PBXContainerItemProxy; 278 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 279 | proxyType = 2; 280 | remoteGlobalIDString = AE4864BD1B066F11005DB302; 281 | remoteInfo = "Blindside-iOS-Framework"; 282 | }; 283 | 4C18B1941BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 284 | isa = PBXContainerItemProxy; 285 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 286 | proxyType = 2; 287 | remoteGlobalIDString = AE03FC1A1B0A57DD00013784; 288 | remoteInfo = "Blindside-iOS-Framework BuildTest"; 289 | }; 290 | 4C18B1961BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 291 | isa = PBXContainerItemProxy; 292 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 293 | proxyType = 2; 294 | remoteGlobalIDString = 34E710AB1B9F85210088AB71; 295 | remoteInfo = "Blindside-watchOS"; 296 | }; 297 | 4C18B1981BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 298 | isa = PBXContainerItemProxy; 299 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 300 | proxyType = 2; 301 | remoteGlobalIDString = 34A18BD31B9F887200A65DB3; 302 | remoteInfo = "Blindside-watchOS BuildTest"; 303 | }; 304 | 4C18B19A1BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 305 | isa = PBXContainerItemProxy; 306 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 307 | proxyType = 2; 308 | remoteGlobalIDString = 34A18BDF1B9F887300A65DB3; 309 | remoteInfo = "Blindside-watchOS BuildTest Extension"; 310 | }; 311 | 4C18B19E1BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 312 | isa = PBXContainerItemProxy; 313 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 314 | proxyType = 2; 315 | remoteGlobalIDString = AE4864F81B067620005DB302; 316 | remoteInfo = "Cedar-iOS-Framework"; 317 | }; 318 | 4C18B1A01BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 319 | isa = PBXContainerItemProxy; 320 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 321 | proxyType = 2; 322 | remoteGlobalIDString = AE03FBE91B06C33B00013784; 323 | remoteInfo = "Cedar-iOS-Framework Specs"; 324 | }; 325 | 4C18B1A41BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 326 | isa = PBXContainerItemProxy; 327 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 328 | proxyType = 2; 329 | remoteGlobalIDString = AE48646A1B0668A2005DB302; 330 | remoteInfo = "Deferred-iOS-Framework"; 331 | }; 332 | 4C18B1A61BC4E27100CF54F4 /* PBXContainerItemProxy */ = { 333 | isa = PBXContainerItemProxy; 334 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 335 | proxyType = 2; 336 | remoteGlobalIDString = AE4864931B066A10005DB302; 337 | remoteInfo = "Deferred-OSX-Framework"; 338 | }; 339 | 4C18B1B11BC4E2CC00CF54F4 /* PBXContainerItemProxy */ = { 340 | isa = PBXContainerItemProxy; 341 | containerPortal = 4C1650C118E50CA1000336FD /* Project object */; 342 | proxyType = 1; 343 | remoteGlobalIDString = 4C1650C818E50CA1000336FD; 344 | remoteInfo = BestPractices; 345 | }; 346 | 4C18B1C31BC4E3CD00CF54F4 /* PBXContainerItemProxy */ = { 347 | isa = PBXContainerItemProxy; 348 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 349 | proxyType = 1; 350 | remoteGlobalIDString = AEEE222811DC2B0600029872; 351 | remoteInfo = "Cedar-StaticLib"; 352 | }; 353 | 4C18B1C61BC4E42C00CF54F4 /* PBXContainerItemProxy */ = { 354 | isa = PBXContainerItemProxy; 355 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 356 | proxyType = 1; 357 | remoteGlobalIDString = AEBCCC63168B9AF10056EE83; 358 | remoteInfo = "UIKit+PivotalSpecHelper-StaticLib"; 359 | }; 360 | 4C18B1C81BC4E43000CF54F4 /* PBXContainerItemProxy */ = { 361 | isa = PBXContainerItemProxy; 362 | containerPortal = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 363 | proxyType = 1; 364 | remoteGlobalIDString = AEC40C88174C203700474D2D; 365 | remoteInfo = "UIKit+PivotalSpecHelperStubs-StaticLib"; 366 | }; 367 | 4C833A9818E50DD30011D3C3 /* PBXContainerItemProxy */ = { 368 | isa = PBXContainerItemProxy; 369 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 370 | proxyType = 2; 371 | remoteGlobalIDString = AEEE1FB611DC271300029872; 372 | remoteInfo = Cedar; 373 | }; 374 | 4C833A9A18E50DD30011D3C3 /* PBXContainerItemProxy */ = { 375 | isa = PBXContainerItemProxy; 376 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 377 | proxyType = 2; 378 | remoteGlobalIDString = AEEE218611DC28E200029872; 379 | remoteInfo = Specs; 380 | }; 381 | 4C833A9C18E50DD30011D3C3 /* PBXContainerItemProxy */ = { 382 | isa = PBXContainerItemProxy; 383 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 384 | proxyType = 2; 385 | remoteGlobalIDString = 96A07F0813F276640021974D; 386 | remoteInfo = FocusedSpecs; 387 | }; 388 | 4C833A9E18E50DD30011D3C3 /* PBXContainerItemProxy */ = { 389 | isa = PBXContainerItemProxy; 390 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 391 | proxyType = 2; 392 | remoteGlobalIDString = AEEE222911DC2B0600029872; 393 | remoteInfo = "Cedar-StaticLib"; 394 | }; 395 | 4C833AA018E50DD30011D3C3 /* PBXContainerItemProxy */ = { 396 | isa = PBXContainerItemProxy; 397 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 398 | proxyType = 2; 399 | remoteGlobalIDString = AEEE227611DC2CF900029872; 400 | remoteInfo = iOSSpecs; 401 | }; 402 | 4C833AA218E50DD30011D3C3 /* PBXContainerItemProxy */ = { 403 | isa = PBXContainerItemProxy; 404 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 405 | proxyType = 2; 406 | remoteGlobalIDString = AE02E7E4184EABCD00414F19; 407 | remoteInfo = iOSFrameworkSpecs; 408 | }; 409 | 4C833AA418E50DD30011D3C3 /* PBXContainerItemProxy */ = { 410 | isa = PBXContainerItemProxy; 411 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 412 | proxyType = 2; 413 | remoteGlobalIDString = 96B5F9F6144A81A7000A6A5D; 414 | remoteInfo = OCUnitApp; 415 | }; 416 | 4C833AA818E50DD30011D3C3 /* PBXContainerItemProxy */ = { 417 | isa = PBXContainerItemProxy; 418 | containerPortal = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 419 | proxyType = 2; 420 | remoteGlobalIDString = 1F45A3DD180E4796003C1E36; 421 | remoteInfo = XCUnitAppTests; 422 | }; 423 | 4CA4826918E50FF800E524B6 /* PBXContainerItemProxy */ = { 424 | isa = PBXContainerItemProxy; 425 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 426 | proxyType = 2; 427 | remoteGlobalIDString = 29CAC6E4150292AD00731862; 428 | remoteInfo = Blindside; 429 | }; 430 | 4CA4826B18E50FF800E524B6 /* PBXContainerItemProxy */ = { 431 | isa = PBXContainerItemProxy; 432 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 433 | proxyType = 2; 434 | remoteGlobalIDString = 29CAC7001502932000731862; 435 | remoteInfo = Specs; 436 | }; 437 | 4CA4826D18E50FF800E524B6 /* PBXContainerItemProxy */ = { 438 | isa = PBXContainerItemProxy; 439 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 440 | proxyType = 2; 441 | remoteGlobalIDString = 29997B471505EC0B00C12110; 442 | remoteInfo = "Blindside-StaticLib"; 443 | }; 444 | 4CA4826F18E5100700E524B6 /* PBXContainerItemProxy */ = { 445 | isa = PBXContainerItemProxy; 446 | containerPortal = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 447 | proxyType = 1; 448 | remoteGlobalIDString = 29997B461505EC0B00C12110; 449 | remoteInfo = "Blindside-StaticLib"; 450 | }; 451 | 4CA4827C18E5106800E524B6 /* PBXContainerItemProxy */ = { 452 | isa = PBXContainerItemProxy; 453 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 454 | proxyType = 2; 455 | remoteGlobalIDString = E18A7B1515674D9B0083D745; 456 | remoteInfo = Deferred; 457 | }; 458 | 4CA4827E18E5106800E524B6 /* PBXContainerItemProxy */ = { 459 | isa = PBXContainerItemProxy; 460 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 461 | proxyType = 2; 462 | remoteGlobalIDString = E18A7B3015674EC20083D745; 463 | remoteInfo = "Deferred-OSX"; 464 | }; 465 | 4CA4828218E5107700E524B6 /* PBXContainerItemProxy */ = { 466 | isa = PBXContainerItemProxy; 467 | containerPortal = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 468 | proxyType = 1; 469 | remoteGlobalIDString = E18A7B1415674D9B0083D745; 470 | remoteInfo = Deferred; 471 | }; 472 | /* End PBXContainerItemProxy section */ 473 | 474 | /* Begin PBXFileReference section */ 475 | 2225F038A06F1D4D1EB0B2D8 /* JSONClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONClient.h; sourceTree = ""; }; 476 | 2225F182E9479D9347EBA74A /* ArtistViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArtistViewController.m; sourceTree = ""; }; 477 | 2225F2505B1A22EAFBA465A9 /* InjectorProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectorProvider.h; sourceTree = ""; }; 478 | 2225F3025C16CE3BBA32DDE9 /* ArtistViewControllerSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArtistViewControllerSpec.mm; sourceTree = ""; }; 479 | 2225F31DE7A12821D08FB6D8 /* HTTPClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPClient.m; sourceTree = ""; }; 480 | 2225F5A602D89DA85B78DBD2 /* artists.json */ = {isa = PBXFileReference; lastKnownFileType = file.json; path = artists.json; sourceTree = ""; }; 481 | 2225F6CA33682145B828BC8D /* HTTPClientSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTTPClientSpec.mm; sourceTree = ""; }; 482 | 2225F7D69CE3204D81E2C21A /* FoundationModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FoundationModule.m; sourceTree = ""; }; 483 | 2225F8BA27105B8EC773EE8D /* JSONClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONClient.m; sourceTree = ""; }; 484 | 2225F92CBED5E79032067389 /* InjectorProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InjectorProvider.m; sourceTree = ""; }; 485 | 2225F9FEDEF77FFBD57BF6FA /* NetworkModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkModule.h; sourceTree = ""; }; 486 | 2225FB862053BDF37895A4C6 /* HTTPClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPClient.h; sourceTree = ""; }; 487 | 2225FB87FF291BDC4ABDA95D /* ArtistViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArtistViewController.h; sourceTree = ""; }; 488 | 2225FBFF7DE7C89C66D1FA71 /* RequestProviderSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RequestProviderSpec.mm; sourceTree = ""; }; 489 | 2225FDE9BB696E631352A547 /* NetworkModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkModule.m; sourceTree = ""; }; 490 | 2225FF83F6A1F3603EF1DE61 /* JSONClientSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSONClientSpec.mm; sourceTree = ""; }; 491 | 2225FFF8E0C1013B1F990D53 /* FoundationModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FoundationModule.h; sourceTree = ""; }; 492 | 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = UIKit.xcodeproj; path = PivotalCoreKit/UIKit/UIKit.xcodeproj; sourceTree = ""; }; 493 | 4C0B92FE1ACF5D7100DE75AC /* Launch Screen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "Launch Screen.xib"; sourceTree = ""; }; 494 | 4C1650C918E50CA1000336FD /* BestPractices.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BestPractices.app; sourceTree = BUILT_PRODUCTS_DIR; }; 495 | 4C1650CC18E50CA1000336FD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 496 | 4C1650CE18E50CA1000336FD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 497 | 4C1650D018E50CA1000336FD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 498 | 4C1650D418E50CA1000336FD /* BestPractices-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BestPractices-Info.plist"; sourceTree = ""; }; 499 | 4C1650D818E50CA1000336FD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 500 | 4C1650DB18E50CA1000336FD /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 501 | 4C1650DC18E50CA1000336FD /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 502 | 4C1650DE18E50CA1000336FD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 503 | 4C1650E518E50CA1000336FD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 504 | 4C18B1AC1BC4E2CB00CF54F4 /* BestPracticesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BestPracticesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 505 | 4C8145A718E5133900FA565A /* AppDelegateSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegateSpec.mm; sourceTree = ""; }; 506 | 4C8145B718E5169700FA565A /* ArtistsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArtistsViewController.h; sourceTree = ""; }; 507 | 4C8145B818E5169700FA565A /* ArtistsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArtistsViewController.m; sourceTree = ""; }; 508 | 4C8145BA18E5169700FA565A /* UIModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIModule.h; sourceTree = ""; }; 509 | 4C8145BB18E5169700FA565A /* UIModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIModule.m; sourceTree = ""; }; 510 | 4C8145C018E5173700FA565A /* InjectorKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectorKeys.h; sourceTree = ""; }; 511 | 4C8145C118E5173700FA565A /* InjectorKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InjectorKeys.m; sourceTree = ""; }; 512 | 4C8145C818E5194900FA565A /* ArtistsViewControllerSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArtistsViewControllerSpec.mm; sourceTree = ""; }; 513 | 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Cedar.xcodeproj; path = cedar/Cedar.xcodeproj; sourceTree = ""; }; 514 | 4CA3C85918E77B3B0082556D /* CellPresenterDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CellPresenterDataSource.h; sourceTree = ""; }; 515 | 4CA3C85A18E77B3B0082556D /* CellPresenterDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CellPresenterDataSource.m; sourceTree = ""; }; 516 | 4CA3C85D18E77BB70082556D /* ArtistsPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArtistsPresenter.h; sourceTree = ""; }; 517 | 4CA3C85E18E77BB70082556D /* ArtistsPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArtistsPresenter.m; sourceTree = ""; }; 518 | 4CA3C86218E77C840082556D /* ArtistsService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArtistsService.h; sourceTree = ""; }; 519 | 4CA3C86318E77C840082556D /* ArtistsService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArtistsService.m; sourceTree = ""; }; 520 | 4CA3C86B18E78A780082556D /* CellPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CellPresenter.h; sourceTree = ""; }; 521 | 4CA3C88218E78E070082556D /* CellPresenterDataSourceSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CellPresenterDataSourceSpec.mm; sourceTree = ""; }; 522 | 4CA4824D18E50EE900E524B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 523 | 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Blindside.xcodeproj; path = blindside/Blindside.xcodeproj; sourceTree = ""; }; 524 | 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Deferred.xcodeproj; path = deferred/Deferred.xcodeproj; sourceTree = ""; }; 525 | 4CAA2CEE18E79C9B00488E9B /* Artist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Artist.h; sourceTree = ""; }; 526 | 4CAA2CEF18E79C9B00488E9B /* Artist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Artist.m; sourceTree = ""; }; 527 | 4CAA2CF218E79CEA00488E9B /* ArtistCellPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArtistCellPresenter.h; sourceTree = ""; }; 528 | 4CAA2CF318E79CEA00488E9B /* ArtistCellPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArtistCellPresenter.m; sourceTree = ""; }; 529 | 4CAB2EA51ACF600B002AB81E /* RequestProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequestProvider.h; sourceTree = ""; }; 530 | 4CAB2EA61ACF600B002AB81E /* RequestProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RequestProvider.m; sourceTree = ""; }; 531 | 4CBB0C3F1AD0715F00F03491 /* ArtistsServiceSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArtistsServiceSpec.mm; sourceTree = ""; }; 532 | AE0D92EB18EF5BE40043F06A /* ArtistCellPresenterSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArtistCellPresenterSpec.mm; sourceTree = ""; }; 533 | AE0D92FC18EF6B2F0043F06A /* ArtistsPresenterSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArtistsPresenterSpec.mm; sourceTree = ""; }; 534 | AE0D92FF18EF6CB30043F06A /* FakeCellPresenterDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FakeCellPresenterDataSource.h; sourceTree = ""; }; 535 | AE0D930018EF6CB30043F06A /* FakeCellPresenterDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FakeCellPresenterDataSource.m; sourceTree = ""; }; 536 | /* End PBXFileReference section */ 537 | 538 | /* Begin PBXFrameworksBuildPhase section */ 539 | 4C1650C618E50CA1000336FD /* Frameworks */ = { 540 | isa = PBXFrameworksBuildPhase; 541 | buildActionMask = 2147483647; 542 | files = ( 543 | 4CA4827118E5100B00E524B6 /* libBlindside-StaticLib.a in Frameworks */, 544 | 4CA4828418E5107C00E524B6 /* libDeferred.a in Frameworks */, 545 | 4C1650CF18E50CA1000336FD /* CoreGraphics.framework in Frameworks */, 546 | 4C1650D118E50CA1000336FD /* UIKit.framework in Frameworks */, 547 | 4C1650CD18E50CA1000336FD /* Foundation.framework in Frameworks */, 548 | ); 549 | runOnlyForDeploymentPostprocessing = 0; 550 | }; 551 | 4C18B1A91BC4E2CB00CF54F4 /* Frameworks */ = { 552 | isa = PBXFrameworksBuildPhase; 553 | buildActionMask = 2147483647; 554 | files = ( 555 | 4C18B1C51BC4E3D200CF54F4 /* libCedar.a in Frameworks */, 556 | 4C18B1CA1BC4E43900CF54F4 /* libUIKit+PivotalSpecHelper-StaticLib.a in Frameworks */, 557 | 4C18B1CB1BC4E43C00CF54F4 /* libUIKit+PivotalSpecHelperStubs-StaticLib.a in Frameworks */, 558 | ); 559 | runOnlyForDeploymentPostprocessing = 0; 560 | }; 561 | /* End PBXFrameworksBuildPhase section */ 562 | 563 | /* Begin PBXGroup section */ 564 | 2225F6051E7FBA8A2520675C /* Fixtures */ = { 565 | isa = PBXGroup; 566 | children = ( 567 | 2225F5A602D89DA85B78DBD2 /* artists.json */, 568 | ); 569 | path = Fixtures; 570 | sourceTree = ""; 571 | }; 572 | 2225F89358E509AF97A1D4CC /* Network */ = { 573 | isa = PBXGroup; 574 | children = ( 575 | 4CBB0C3F1AD0715F00F03491 /* ArtistsServiceSpec.mm */, 576 | 2225F6CA33682145B828BC8D /* HTTPClientSpec.mm */, 577 | 2225FF83F6A1F3603EF1DE61 /* JSONClientSpec.mm */, 578 | 2225FBFF7DE7C89C66D1FA71 /* RequestProviderSpec.mm */, 579 | ); 580 | path = Network; 581 | sourceTree = ""; 582 | }; 583 | 4C04CDE61AF868DD005DA4D6 /* Products */ = { 584 | isa = PBXGroup; 585 | children = ( 586 | 4C04CE031AF868DE005DA4D6 /* libUIKit+PivotalCore-StaticLib.a */, 587 | 4C04CE051AF868DE005DA4D6 /* libUIKit+PivotalSpecHelper-StaticLib.a */, 588 | 4C04CE071AF868DE005DA4D6 /* libUIKit+PivotalSpecHelperStubs-StaticLib.a */, 589 | 4C0C9DD81C4F68B4006DA0BF /* UIKit_PivotalCore.framework */, 590 | 4C0C9DDA1C4F68B4006DA0BF /* UIKit_PivotalCore.framework */, 591 | 4C0C9DDC1C4F68B4006DA0BF /* UIKit_PivotalSpecHelper.framework */, 592 | 4C0C9DDE1C4F68B4006DA0BF /* UIKit_PivotalSpecHelper.framework */, 593 | 4C0C9DE01C4F68B4006DA0BF /* UIKit_PivotalSpecHelperStubs.framework */, 594 | 4C0C9DE21C4F68B4006DA0BF /* UIKit_PivotalSpecHelperStubs.framework */, 595 | 4C04CE091AF868DE005DA4D6 /* UIKit-StaticLibSpec.app */, 596 | 4C04CE0B1AF868DE005DA4D6 /* UIKit-StaticLibSpecBundle.xctest */, 597 | 4C0C9DE41C4F68B4006DA0BF /* UIKit-tvOS SpecHost.app */, 598 | 4C0C9DE61C4F68B4006DA0BF /* UIKit-tvOS SpecBundle.xctest */, 599 | 4C0C9DE81C4F68B4006DA0BF /* UIKit-iOS SpecHost.app */, 600 | 4C0C9DEA1C4F68B4006DA0BF /* UIKit-iOS SpecBundle.xctest */, 601 | ); 602 | name = Products; 603 | sourceTree = ""; 604 | }; 605 | 4C1650C018E50CA1000336FD = { 606 | isa = PBXGroup; 607 | children = ( 608 | 4C1650D218E50CA1000336FD /* BestPractices */, 609 | 4CA4824B18E50EE900E524B6 /* BestPracticesTests */, 610 | 4C833A8918E50DBE0011D3C3 /* Externals */, 611 | 4C1650CB18E50CA1000336FD /* Frameworks */, 612 | 4C1650CA18E50CA1000336FD /* Products */, 613 | ); 614 | sourceTree = ""; 615 | }; 616 | 4C1650CA18E50CA1000336FD /* Products */ = { 617 | isa = PBXGroup; 618 | children = ( 619 | 4C1650C918E50CA1000336FD /* BestPractices.app */, 620 | 4C18B1AC1BC4E2CB00CF54F4 /* BestPracticesTests.xctest */, 621 | ); 622 | name = Products; 623 | sourceTree = ""; 624 | }; 625 | 4C1650CB18E50CA1000336FD /* Frameworks */ = { 626 | isa = PBXGroup; 627 | children = ( 628 | 4C1650CC18E50CA1000336FD /* Foundation.framework */, 629 | 4C1650CE18E50CA1000336FD /* CoreGraphics.framework */, 630 | 4C1650D018E50CA1000336FD /* UIKit.framework */, 631 | 4C1650E518E50CA1000336FD /* XCTest.framework */, 632 | ); 633 | name = Frameworks; 634 | sourceTree = ""; 635 | }; 636 | 4C1650D218E50CA1000336FD /* BestPractices */ = { 637 | isa = PBXGroup; 638 | children = ( 639 | 4C1650DB18E50CA1000336FD /* AppDelegate.h */, 640 | 4C1650DC18E50CA1000336FD /* AppDelegate.m */, 641 | 4C8145B618E5169700FA565A /* Controllers */, 642 | 4C1650DE18E50CA1000336FD /* Images.xcassets */, 643 | 4C0B92FE1ACF5D7100DE75AC /* Launch Screen.xib */, 644 | 4CAA2CED18E79C8A00488E9B /* Models */, 645 | 4C8145B918E5169700FA565A /* Modules */, 646 | 4CA3C86118E77C260082556D /* Network */, 647 | 4CA3C84918E77B270082556D /* Presenters */, 648 | 4C1650D318E50CA1000336FD /* Supporting Files */, 649 | ); 650 | path = BestPractices; 651 | sourceTree = ""; 652 | }; 653 | 4C1650D318E50CA1000336FD /* Supporting Files */ = { 654 | isa = PBXGroup; 655 | children = ( 656 | 4C1650D418E50CA1000336FD /* BestPractices-Info.plist */, 657 | 4C1650D818E50CA1000336FD /* main.m */, 658 | ); 659 | name = "Supporting Files"; 660 | sourceTree = ""; 661 | }; 662 | 4C8145B618E5169700FA565A /* Controllers */ = { 663 | isa = PBXGroup; 664 | children = ( 665 | 4C8145B718E5169700FA565A /* ArtistsViewController.h */, 666 | 4C8145B818E5169700FA565A /* ArtistsViewController.m */, 667 | 2225FB87FF291BDC4ABDA95D /* ArtistViewController.h */, 668 | 2225F182E9479D9347EBA74A /* ArtistViewController.m */, 669 | ); 670 | path = Controllers; 671 | sourceTree = ""; 672 | }; 673 | 4C8145B918E5169700FA565A /* Modules */ = { 674 | isa = PBXGroup; 675 | children = ( 676 | 4C8145C018E5173700FA565A /* InjectorKeys.h */, 677 | 4C8145C118E5173700FA565A /* InjectorKeys.m */, 678 | 4C8145BA18E5169700FA565A /* UIModule.h */, 679 | 4C8145BB18E5169700FA565A /* UIModule.m */, 680 | 2225FDE9BB696E631352A547 /* NetworkModule.m */, 681 | 2225F9FEDEF77FFBD57BF6FA /* NetworkModule.h */, 682 | 2225F92CBED5E79032067389 /* InjectorProvider.m */, 683 | 2225F2505B1A22EAFBA465A9 /* InjectorProvider.h */, 684 | 2225F7D69CE3204D81E2C21A /* FoundationModule.m */, 685 | 2225FFF8E0C1013B1F990D53 /* FoundationModule.h */, 686 | ); 687 | path = Modules; 688 | sourceTree = ""; 689 | }; 690 | 4C8145C718E5194900FA565A /* Controllers */ = { 691 | isa = PBXGroup; 692 | children = ( 693 | 4C8145C818E5194900FA565A /* ArtistsViewControllerSpec.mm */, 694 | 2225F3025C16CE3BBA32DDE9 /* ArtistViewControllerSpec.mm */, 695 | ); 696 | path = Controllers; 697 | sourceTree = ""; 698 | }; 699 | 4C833A8918E50DBE0011D3C3 /* Externals */ = { 700 | isa = PBXGroup; 701 | children = ( 702 | 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */, 703 | 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */, 704 | 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */, 705 | 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */, 706 | ); 707 | path = Externals; 708 | sourceTree = ""; 709 | }; 710 | 4C833A8B18E50DD30011D3C3 /* Products */ = { 711 | isa = PBXGroup; 712 | children = ( 713 | 4C833A9918E50DD30011D3C3 /* Cedar.framework */, 714 | 4C18B19F1BC4E27100CF54F4 /* Cedar.framework */, 715 | 4C0C9DA91C4F68B4006DA0BF /* Cedar.framework */, 716 | 4C0C9DAB1C4F68B4006DA0BF /* Cedar.framework */, 717 | 4C833A9F18E50DD30011D3C3 /* libCedar.a */, 718 | 4C833A9B18E50DD30011D3C3 /* Cedar-OSX Specs */, 719 | 4C833A9D18E50DD30011D3C3 /* Cedar-OSX FocusedSpecs */, 720 | 4C18B1A11BC4E27100CF54F4 /* Cedar-iOS Specs.app */, 721 | 4C833AA118E50DD30011D3C3 /* Cedar-iOS StaticLib Specs.app */, 722 | 4C833AA318E50DD30011D3C3 /* Cedar-iOS StaticFrameworkSpecs.app */, 723 | 4C0B92EB1ACF598000DE75AC /* Cedar-OSX HostApp.app */, 724 | 4C833AA518E50DD30011D3C3 /* Cedar-iOS HostApp.app */, 725 | 4C0C9DAD1C4F68B4006DA0BF /* Cedar-watchOS HostApp.app */, 726 | 4C0B92ED1ACF598000DE75AC /* Cedar-OSX SpecBundle.xctest */, 727 | 4C833AA918E50DD30011D3C3 /* Cedar-iOS SpecBundle.xctest */, 728 | 4C0C9DAF1C4F68B4006DA0BF /* Cedar-watchOS Specs.app */, 729 | 4C0C9DB11C4F68B4006DA0BF /* Cedar-watchOS Specs Extension.appex */, 730 | 4C0C9DB31C4F68B4006DA0BF /* Cedar-tvOS SpecBundle.xctest */, 731 | ); 732 | name = Products; 733 | sourceTree = ""; 734 | }; 735 | 4CA3C84918E77B270082556D /* Presenters */ = { 736 | isa = PBXGroup; 737 | children = ( 738 | 4CAA2CF218E79CEA00488E9B /* ArtistCellPresenter.h */, 739 | 4CAA2CF318E79CEA00488E9B /* ArtistCellPresenter.m */, 740 | 4CA3C85D18E77BB70082556D /* ArtistsPresenter.h */, 741 | 4CA3C85E18E77BB70082556D /* ArtistsPresenter.m */, 742 | 4CA3C86B18E78A780082556D /* CellPresenter.h */, 743 | 4CA3C85918E77B3B0082556D /* CellPresenterDataSource.h */, 744 | 4CA3C85A18E77B3B0082556D /* CellPresenterDataSource.m */, 745 | ); 746 | path = Presenters; 747 | sourceTree = ""; 748 | }; 749 | 4CA3C86118E77C260082556D /* Network */ = { 750 | isa = PBXGroup; 751 | children = ( 752 | 4CA3C86218E77C840082556D /* ArtistsService.h */, 753 | 4CA3C86318E77C840082556D /* ArtistsService.m */, 754 | 2225FB862053BDF37895A4C6 /* HTTPClient.h */, 755 | 2225F31DE7A12821D08FB6D8 /* HTTPClient.m */, 756 | 2225F038A06F1D4D1EB0B2D8 /* JSONClient.h */, 757 | 2225F8BA27105B8EC773EE8D /* JSONClient.m */, 758 | 4CAB2EA51ACF600B002AB81E /* RequestProvider.h */, 759 | 4CAB2EA61ACF600B002AB81E /* RequestProvider.m */, 760 | ); 761 | path = Network; 762 | sourceTree = ""; 763 | }; 764 | 4CA3C87B18E78AE20082556D /* Presenters */ = { 765 | isa = PBXGroup; 766 | children = ( 767 | AE0D92EB18EF5BE40043F06A /* ArtistCellPresenterSpec.mm */, 768 | AE0D92FC18EF6B2F0043F06A /* ArtistsPresenterSpec.mm */, 769 | 4CA3C88218E78E070082556D /* CellPresenterDataSourceSpec.mm */, 770 | ); 771 | path = Presenters; 772 | sourceTree = ""; 773 | }; 774 | 4CA4824B18E50EE900E524B6 /* BestPracticesTests */ = { 775 | isa = PBXGroup; 776 | children = ( 777 | 4C8145A718E5133900FA565A /* AppDelegateSpec.mm */, 778 | 4C8145C718E5194900FA565A /* Controllers */, 779 | AE0D92FE18EF6C9E0043F06A /* Fakes */, 780 | 2225F6051E7FBA8A2520675C /* Fixtures */, 781 | 2225F89358E509AF97A1D4CC /* Network */, 782 | 4CA3C87B18E78AE20082556D /* Presenters */, 783 | 4CA4824C18E50EE900E524B6 /* Supporting Files */, 784 | ); 785 | path = BestPracticesTests; 786 | sourceTree = ""; 787 | }; 788 | 4CA4824C18E50EE900E524B6 /* Supporting Files */ = { 789 | isa = PBXGroup; 790 | children = ( 791 | 4CA4824D18E50EE900E524B6 /* Info.plist */, 792 | ); 793 | name = "Supporting Files"; 794 | sourceTree = ""; 795 | }; 796 | 4CA4826218E50FF800E524B6 /* Products */ = { 797 | isa = PBXGroup; 798 | children = ( 799 | 4CA4826A18E50FF800E524B6 /* Blindside.framework */, 800 | 4C18B1931BC4E27100CF54F4 /* Blindside.framework */, 801 | 4C18B1971BC4E27100CF54F4 /* Blindside.framework */, 802 | 4C0C9D931C4F68B4006DA0BF /* Blindside.framework */, 803 | 4CA4826E18E50FF800E524B6 /* libBlindside-StaticLib.a */, 804 | 4CA4826C18E50FF800E524B6 /* Specs */, 805 | 4C18B1951BC4E27100CF54F4 /* Blindside-iOS BuildTest.app */, 806 | 4C18B1991BC4E27100CF54F4 /* Blindside-watchOS BuildTest.app */, 807 | 4C18B19B1BC4E27100CF54F4 /* Blindside-watchOS BuildTest Extension.appex */, 808 | 4C0C9D951C4F68B4006DA0BF /* Blindside-tvOS BuildTest.app */, 809 | ); 810 | name = Products; 811 | sourceTree = ""; 812 | }; 813 | 4CA4827618E5106800E524B6 /* Products */ = { 814 | isa = PBXGroup; 815 | children = ( 816 | 4CA4827D18E5106800E524B6 /* libDeferred.a */, 817 | 4CA4827F18E5106800E524B6 /* libDeferred-OSX.a */, 818 | 4C0C9DBF1C4F68B4006DA0BF /* libDeferred-watchOS.a */, 819 | 4C0C9DC11C4F68B4006DA0BF /* libDeferred-tvOS.a */, 820 | 4C18B1A51BC4E27100CF54F4 /* KSDeferred.framework */, 821 | 4C18B1A71BC4E27100CF54F4 /* KSDeferred.framework */, 822 | 4C0C9DC31C4F68B4006DA0BF /* KSDeferred.framework */, 823 | 4C0C9DC51C4F68B4006DA0BF /* KSDeferred.framework */, 824 | 4C0B92F41ACF598000DE75AC /* Deferred-iOSSpecs.xctest */, 825 | 4C0B92F61ACF598000DE75AC /* Deferred-OSXSpecs.xctest */, 826 | 4C0C9DC71C4F68B4006DA0BF /* Deferred-tvOSSpecs.xctest */, 827 | ); 828 | name = Products; 829 | sourceTree = ""; 830 | }; 831 | 4CAA2CED18E79C8A00488E9B /* Models */ = { 832 | isa = PBXGroup; 833 | children = ( 834 | 4CAA2CEE18E79C9B00488E9B /* Artist.h */, 835 | 4CAA2CEF18E79C9B00488E9B /* Artist.m */, 836 | ); 837 | path = Models; 838 | sourceTree = ""; 839 | }; 840 | AE0D92FE18EF6C9E0043F06A /* Fakes */ = { 841 | isa = PBXGroup; 842 | children = ( 843 | AE0D92FF18EF6CB30043F06A /* FakeCellPresenterDataSource.h */, 844 | AE0D930018EF6CB30043F06A /* FakeCellPresenterDataSource.m */, 845 | ); 846 | path = Fakes; 847 | sourceTree = ""; 848 | }; 849 | /* End PBXGroup section */ 850 | 851 | /* Begin PBXNativeTarget section */ 852 | 4C1650C818E50CA1000336FD /* BestPractices */ = { 853 | isa = PBXNativeTarget; 854 | buildConfigurationList = 4C1650F518E50CA1000336FD /* Build configuration list for PBXNativeTarget "BestPractices" */; 855 | buildPhases = ( 856 | 4C1650C518E50CA1000336FD /* Sources */, 857 | 4C1650C618E50CA1000336FD /* Frameworks */, 858 | 4C1650C718E50CA1000336FD /* Resources */, 859 | ); 860 | buildRules = ( 861 | ); 862 | dependencies = ( 863 | 4CA4827018E5100700E524B6 /* PBXTargetDependency */, 864 | 4CA4828318E5107700E524B6 /* PBXTargetDependency */, 865 | ); 866 | name = BestPractices; 867 | productName = BestPractices; 868 | productReference = 4C1650C918E50CA1000336FD /* BestPractices.app */; 869 | productType = "com.apple.product-type.application"; 870 | }; 871 | 4C18B1AB1BC4E2CB00CF54F4 /* BestPracticesTests */ = { 872 | isa = PBXNativeTarget; 873 | buildConfigurationList = 4C18B1B31BC4E2CC00CF54F4 /* Build configuration list for PBXNativeTarget "BestPracticesTests" */; 874 | buildPhases = ( 875 | 4C18B1A81BC4E2CB00CF54F4 /* Sources */, 876 | 4C18B1A91BC4E2CB00CF54F4 /* Frameworks */, 877 | 4C18B1AA1BC4E2CB00CF54F4 /* Resources */, 878 | ); 879 | buildRules = ( 880 | ); 881 | dependencies = ( 882 | 4C18B1B21BC4E2CC00CF54F4 /* PBXTargetDependency */, 883 | 4C18B1C41BC4E3CD00CF54F4 /* PBXTargetDependency */, 884 | 4C18B1C71BC4E42C00CF54F4 /* PBXTargetDependency */, 885 | 4C18B1C91BC4E43000CF54F4 /* PBXTargetDependency */, 886 | ); 887 | name = BestPracticesTests; 888 | productName = BestPracticesTests; 889 | productReference = 4C18B1AC1BC4E2CB00CF54F4 /* BestPracticesTests.xctest */; 890 | productType = "com.apple.product-type.bundle.unit-test"; 891 | }; 892 | /* End PBXNativeTarget section */ 893 | 894 | /* Begin PBXProject section */ 895 | 4C1650C118E50CA1000336FD /* Project object */ = { 896 | isa = PBXProject; 897 | attributes = { 898 | LastUpgradeCheck = 0700; 899 | ORGANIZATIONNAME = CBG; 900 | TargetAttributes = { 901 | 4C18B1AB1BC4E2CB00CF54F4 = { 902 | CreatedOnToolsVersion = 7.0.1; 903 | TestTargetID = 4C1650C818E50CA1000336FD; 904 | }; 905 | }; 906 | }; 907 | buildConfigurationList = 4C1650C418E50CA1000336FD /* Build configuration list for PBXProject "BestPractices" */; 908 | compatibilityVersion = "Xcode 3.2"; 909 | developmentRegion = English; 910 | hasScannedForEncodings = 0; 911 | knownRegions = ( 912 | en, 913 | ); 914 | mainGroup = 4C1650C018E50CA1000336FD; 915 | productRefGroup = 4C1650CA18E50CA1000336FD /* Products */; 916 | projectDirPath = ""; 917 | projectReferences = ( 918 | { 919 | ProductGroup = 4CA4826218E50FF800E524B6 /* Products */; 920 | ProjectRef = 4CA4826118E50FF800E524B6 /* Blindside.xcodeproj */; 921 | }, 922 | { 923 | ProductGroup = 4C833A8B18E50DD30011D3C3 /* Products */; 924 | ProjectRef = 4C833A8A18E50DD30011D3C3 /* Cedar.xcodeproj */; 925 | }, 926 | { 927 | ProductGroup = 4CA4827618E5106800E524B6 /* Products */; 928 | ProjectRef = 4CA4827518E5106800E524B6 /* Deferred.xcodeproj */; 929 | }, 930 | { 931 | ProductGroup = 4C04CDE61AF868DD005DA4D6 /* Products */; 932 | ProjectRef = 4C04CDE51AF868DD005DA4D6 /* UIKit.xcodeproj */; 933 | }, 934 | ); 935 | projectRoot = ""; 936 | targets = ( 937 | 4C1650C818E50CA1000336FD /* BestPractices */, 938 | 4C18B1AB1BC4E2CB00CF54F4 /* BestPracticesTests */, 939 | ); 940 | }; 941 | /* End PBXProject section */ 942 | 943 | /* Begin PBXReferenceProxy section */ 944 | 4C04CE031AF868DE005DA4D6 /* libUIKit+PivotalCore-StaticLib.a */ = { 945 | isa = PBXReferenceProxy; 946 | fileType = archive.ar; 947 | path = "libUIKit+PivotalCore-StaticLib.a"; 948 | remoteRef = 4C04CE021AF868DE005DA4D6 /* PBXContainerItemProxy */; 949 | sourceTree = BUILT_PRODUCTS_DIR; 950 | }; 951 | 4C04CE051AF868DE005DA4D6 /* libUIKit+PivotalSpecHelper-StaticLib.a */ = { 952 | isa = PBXReferenceProxy; 953 | fileType = archive.ar; 954 | path = "libUIKit+PivotalSpecHelper-StaticLib.a"; 955 | remoteRef = 4C04CE041AF868DE005DA4D6 /* PBXContainerItemProxy */; 956 | sourceTree = BUILT_PRODUCTS_DIR; 957 | }; 958 | 4C04CE071AF868DE005DA4D6 /* libUIKit+PivotalSpecHelperStubs-StaticLib.a */ = { 959 | isa = PBXReferenceProxy; 960 | fileType = archive.ar; 961 | path = "libUIKit+PivotalSpecHelperStubs-StaticLib.a"; 962 | remoteRef = 4C04CE061AF868DE005DA4D6 /* PBXContainerItemProxy */; 963 | sourceTree = BUILT_PRODUCTS_DIR; 964 | }; 965 | 4C04CE091AF868DE005DA4D6 /* UIKit-StaticLibSpec.app */ = { 966 | isa = PBXReferenceProxy; 967 | fileType = wrapper.application; 968 | path = "UIKit-StaticLibSpec.app"; 969 | remoteRef = 4C04CE081AF868DE005DA4D6 /* PBXContainerItemProxy */; 970 | sourceTree = BUILT_PRODUCTS_DIR; 971 | }; 972 | 4C04CE0B1AF868DE005DA4D6 /* UIKit-StaticLibSpecBundle.xctest */ = { 973 | isa = PBXReferenceProxy; 974 | fileType = wrapper.cfbundle; 975 | path = "UIKit-StaticLibSpecBundle.xctest"; 976 | remoteRef = 4C04CE0A1AF868DE005DA4D6 /* PBXContainerItemProxy */; 977 | sourceTree = BUILT_PRODUCTS_DIR; 978 | }; 979 | 4C0B92EB1ACF598000DE75AC /* Cedar-OSX HostApp.app */ = { 980 | isa = PBXReferenceProxy; 981 | fileType = wrapper.application; 982 | path = "Cedar-OSX HostApp.app"; 983 | remoteRef = 4C0B92EA1ACF598000DE75AC /* PBXContainerItemProxy */; 984 | sourceTree = BUILT_PRODUCTS_DIR; 985 | }; 986 | 4C0B92ED1ACF598000DE75AC /* Cedar-OSX SpecBundle.xctest */ = { 987 | isa = PBXReferenceProxy; 988 | fileType = wrapper.cfbundle; 989 | path = "Cedar-OSX SpecBundle.xctest"; 990 | remoteRef = 4C0B92EC1ACF598000DE75AC /* PBXContainerItemProxy */; 991 | sourceTree = BUILT_PRODUCTS_DIR; 992 | }; 993 | 4C0B92F41ACF598000DE75AC /* Deferred-iOSSpecs.xctest */ = { 994 | isa = PBXReferenceProxy; 995 | fileType = wrapper.cfbundle; 996 | path = "Deferred-iOSSpecs.xctest"; 997 | remoteRef = 4C0B92F31ACF598000DE75AC /* PBXContainerItemProxy */; 998 | sourceTree = BUILT_PRODUCTS_DIR; 999 | }; 1000 | 4C0B92F61ACF598000DE75AC /* Deferred-OSXSpecs.xctest */ = { 1001 | isa = PBXReferenceProxy; 1002 | fileType = wrapper.cfbundle; 1003 | path = "Deferred-OSXSpecs.xctest"; 1004 | remoteRef = 4C0B92F51ACF598000DE75AC /* PBXContainerItemProxy */; 1005 | sourceTree = BUILT_PRODUCTS_DIR; 1006 | }; 1007 | 4C0C9D931C4F68B4006DA0BF /* Blindside.framework */ = { 1008 | isa = PBXReferenceProxy; 1009 | fileType = wrapper.framework; 1010 | path = Blindside.framework; 1011 | remoteRef = 4C0C9D921C4F68B4006DA0BF /* PBXContainerItemProxy */; 1012 | sourceTree = BUILT_PRODUCTS_DIR; 1013 | }; 1014 | 4C0C9D951C4F68B4006DA0BF /* Blindside-tvOS BuildTest.app */ = { 1015 | isa = PBXReferenceProxy; 1016 | fileType = wrapper.application; 1017 | path = "Blindside-tvOS BuildTest.app"; 1018 | remoteRef = 4C0C9D941C4F68B4006DA0BF /* PBXContainerItemProxy */; 1019 | sourceTree = BUILT_PRODUCTS_DIR; 1020 | }; 1021 | 4C0C9DA91C4F68B4006DA0BF /* Cedar.framework */ = { 1022 | isa = PBXReferenceProxy; 1023 | fileType = wrapper.framework; 1024 | path = Cedar.framework; 1025 | remoteRef = 4C0C9DA81C4F68B4006DA0BF /* PBXContainerItemProxy */; 1026 | sourceTree = BUILT_PRODUCTS_DIR; 1027 | }; 1028 | 4C0C9DAB1C4F68B4006DA0BF /* Cedar.framework */ = { 1029 | isa = PBXReferenceProxy; 1030 | fileType = wrapper.framework; 1031 | path = Cedar.framework; 1032 | remoteRef = 4C0C9DAA1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1033 | sourceTree = BUILT_PRODUCTS_DIR; 1034 | }; 1035 | 4C0C9DAD1C4F68B4006DA0BF /* Cedar-watchOS HostApp.app */ = { 1036 | isa = PBXReferenceProxy; 1037 | fileType = wrapper.application; 1038 | path = "Cedar-watchOS HostApp.app"; 1039 | remoteRef = 4C0C9DAC1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1040 | sourceTree = BUILT_PRODUCTS_DIR; 1041 | }; 1042 | 4C0C9DAF1C4F68B4006DA0BF /* Cedar-watchOS Specs.app */ = { 1043 | isa = PBXReferenceProxy; 1044 | fileType = wrapper.application; 1045 | path = "Cedar-watchOS Specs.app"; 1046 | remoteRef = 4C0C9DAE1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1047 | sourceTree = BUILT_PRODUCTS_DIR; 1048 | }; 1049 | 4C0C9DB11C4F68B4006DA0BF /* Cedar-watchOS Specs Extension.appex */ = { 1050 | isa = PBXReferenceProxy; 1051 | fileType = "wrapper.app-extension"; 1052 | path = "Cedar-watchOS Specs Extension.appex"; 1053 | remoteRef = 4C0C9DB01C4F68B4006DA0BF /* PBXContainerItemProxy */; 1054 | sourceTree = BUILT_PRODUCTS_DIR; 1055 | }; 1056 | 4C0C9DB31C4F68B4006DA0BF /* Cedar-tvOS SpecBundle.xctest */ = { 1057 | isa = PBXReferenceProxy; 1058 | fileType = wrapper.cfbundle; 1059 | path = "Cedar-tvOS SpecBundle.xctest"; 1060 | remoteRef = 4C0C9DB21C4F68B4006DA0BF /* PBXContainerItemProxy */; 1061 | sourceTree = BUILT_PRODUCTS_DIR; 1062 | }; 1063 | 4C0C9DBF1C4F68B4006DA0BF /* libDeferred-watchOS.a */ = { 1064 | isa = PBXReferenceProxy; 1065 | fileType = archive.ar; 1066 | path = "libDeferred-watchOS.a"; 1067 | remoteRef = 4C0C9DBE1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1068 | sourceTree = BUILT_PRODUCTS_DIR; 1069 | }; 1070 | 4C0C9DC11C4F68B4006DA0BF /* libDeferred-tvOS.a */ = { 1071 | isa = PBXReferenceProxy; 1072 | fileType = archive.ar; 1073 | path = "libDeferred-tvOS.a"; 1074 | remoteRef = 4C0C9DC01C4F68B4006DA0BF /* PBXContainerItemProxy */; 1075 | sourceTree = BUILT_PRODUCTS_DIR; 1076 | }; 1077 | 4C0C9DC31C4F68B4006DA0BF /* KSDeferred.framework */ = { 1078 | isa = PBXReferenceProxy; 1079 | fileType = wrapper.framework; 1080 | path = KSDeferred.framework; 1081 | remoteRef = 4C0C9DC21C4F68B4006DA0BF /* PBXContainerItemProxy */; 1082 | sourceTree = BUILT_PRODUCTS_DIR; 1083 | }; 1084 | 4C0C9DC51C4F68B4006DA0BF /* KSDeferred.framework */ = { 1085 | isa = PBXReferenceProxy; 1086 | fileType = wrapper.framework; 1087 | path = KSDeferred.framework; 1088 | remoteRef = 4C0C9DC41C4F68B4006DA0BF /* PBXContainerItemProxy */; 1089 | sourceTree = BUILT_PRODUCTS_DIR; 1090 | }; 1091 | 4C0C9DC71C4F68B4006DA0BF /* Deferred-tvOSSpecs.xctest */ = { 1092 | isa = PBXReferenceProxy; 1093 | fileType = wrapper.cfbundle; 1094 | path = "Deferred-tvOSSpecs.xctest"; 1095 | remoteRef = 4C0C9DC61C4F68B4006DA0BF /* PBXContainerItemProxy */; 1096 | sourceTree = BUILT_PRODUCTS_DIR; 1097 | }; 1098 | 4C0C9DD81C4F68B4006DA0BF /* UIKit_PivotalCore.framework */ = { 1099 | isa = PBXReferenceProxy; 1100 | fileType = wrapper.framework; 1101 | path = UIKit_PivotalCore.framework; 1102 | remoteRef = 4C0C9DD71C4F68B4006DA0BF /* PBXContainerItemProxy */; 1103 | sourceTree = BUILT_PRODUCTS_DIR; 1104 | }; 1105 | 4C0C9DDA1C4F68B4006DA0BF /* UIKit_PivotalCore.framework */ = { 1106 | isa = PBXReferenceProxy; 1107 | fileType = wrapper.framework; 1108 | path = UIKit_PivotalCore.framework; 1109 | remoteRef = 4C0C9DD91C4F68B4006DA0BF /* PBXContainerItemProxy */; 1110 | sourceTree = BUILT_PRODUCTS_DIR; 1111 | }; 1112 | 4C0C9DDC1C4F68B4006DA0BF /* UIKit_PivotalSpecHelper.framework */ = { 1113 | isa = PBXReferenceProxy; 1114 | fileType = wrapper.framework; 1115 | path = UIKit_PivotalSpecHelper.framework; 1116 | remoteRef = 4C0C9DDB1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1117 | sourceTree = BUILT_PRODUCTS_DIR; 1118 | }; 1119 | 4C0C9DDE1C4F68B4006DA0BF /* UIKit_PivotalSpecHelper.framework */ = { 1120 | isa = PBXReferenceProxy; 1121 | fileType = wrapper.framework; 1122 | path = UIKit_PivotalSpecHelper.framework; 1123 | remoteRef = 4C0C9DDD1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1124 | sourceTree = BUILT_PRODUCTS_DIR; 1125 | }; 1126 | 4C0C9DE01C4F68B4006DA0BF /* UIKit_PivotalSpecHelperStubs.framework */ = { 1127 | isa = PBXReferenceProxy; 1128 | fileType = wrapper.framework; 1129 | path = UIKit_PivotalSpecHelperStubs.framework; 1130 | remoteRef = 4C0C9DDF1C4F68B4006DA0BF /* PBXContainerItemProxy */; 1131 | sourceTree = BUILT_PRODUCTS_DIR; 1132 | }; 1133 | 4C0C9DE21C4F68B4006DA0BF /* UIKit_PivotalSpecHelperStubs.framework */ = { 1134 | isa = PBXReferenceProxy; 1135 | fileType = wrapper.framework; 1136 | path = UIKit_PivotalSpecHelperStubs.framework; 1137 | remoteRef = 4C0C9DE11C4F68B4006DA0BF /* PBXContainerItemProxy */; 1138 | sourceTree = BUILT_PRODUCTS_DIR; 1139 | }; 1140 | 4C0C9DE41C4F68B4006DA0BF /* UIKit-tvOS SpecHost.app */ = { 1141 | isa = PBXReferenceProxy; 1142 | fileType = wrapper.application; 1143 | path = "UIKit-tvOS SpecHost.app"; 1144 | remoteRef = 4C0C9DE31C4F68B4006DA0BF /* PBXContainerItemProxy */; 1145 | sourceTree = BUILT_PRODUCTS_DIR; 1146 | }; 1147 | 4C0C9DE61C4F68B4006DA0BF /* UIKit-tvOS SpecBundle.xctest */ = { 1148 | isa = PBXReferenceProxy; 1149 | fileType = wrapper.cfbundle; 1150 | path = "UIKit-tvOS SpecBundle.xctest"; 1151 | remoteRef = 4C0C9DE51C4F68B4006DA0BF /* PBXContainerItemProxy */; 1152 | sourceTree = BUILT_PRODUCTS_DIR; 1153 | }; 1154 | 4C0C9DE81C4F68B4006DA0BF /* UIKit-iOS SpecHost.app */ = { 1155 | isa = PBXReferenceProxy; 1156 | fileType = wrapper.application; 1157 | path = "UIKit-iOS SpecHost.app"; 1158 | remoteRef = 4C0C9DE71C4F68B4006DA0BF /* PBXContainerItemProxy */; 1159 | sourceTree = BUILT_PRODUCTS_DIR; 1160 | }; 1161 | 4C0C9DEA1C4F68B4006DA0BF /* UIKit-iOS SpecBundle.xctest */ = { 1162 | isa = PBXReferenceProxy; 1163 | fileType = wrapper.cfbundle; 1164 | path = "UIKit-iOS SpecBundle.xctest"; 1165 | remoteRef = 4C0C9DE91C4F68B4006DA0BF /* PBXContainerItemProxy */; 1166 | sourceTree = BUILT_PRODUCTS_DIR; 1167 | }; 1168 | 4C18B1931BC4E27100CF54F4 /* Blindside.framework */ = { 1169 | isa = PBXReferenceProxy; 1170 | fileType = wrapper.framework; 1171 | path = Blindside.framework; 1172 | remoteRef = 4C18B1921BC4E27100CF54F4 /* PBXContainerItemProxy */; 1173 | sourceTree = BUILT_PRODUCTS_DIR; 1174 | }; 1175 | 4C18B1951BC4E27100CF54F4 /* Blindside-iOS BuildTest.app */ = { 1176 | isa = PBXReferenceProxy; 1177 | fileType = wrapper.application; 1178 | path = "Blindside-iOS BuildTest.app"; 1179 | remoteRef = 4C18B1941BC4E27100CF54F4 /* PBXContainerItemProxy */; 1180 | sourceTree = BUILT_PRODUCTS_DIR; 1181 | }; 1182 | 4C18B1971BC4E27100CF54F4 /* Blindside.framework */ = { 1183 | isa = PBXReferenceProxy; 1184 | fileType = wrapper.framework; 1185 | path = Blindside.framework; 1186 | remoteRef = 4C18B1961BC4E27100CF54F4 /* PBXContainerItemProxy */; 1187 | sourceTree = BUILT_PRODUCTS_DIR; 1188 | }; 1189 | 4C18B1991BC4E27100CF54F4 /* Blindside-watchOS BuildTest.app */ = { 1190 | isa = PBXReferenceProxy; 1191 | fileType = wrapper.application; 1192 | path = "Blindside-watchOS BuildTest.app"; 1193 | remoteRef = 4C18B1981BC4E27100CF54F4 /* PBXContainerItemProxy */; 1194 | sourceTree = BUILT_PRODUCTS_DIR; 1195 | }; 1196 | 4C18B19B1BC4E27100CF54F4 /* Blindside-watchOS BuildTest Extension.appex */ = { 1197 | isa = PBXReferenceProxy; 1198 | fileType = "wrapper.app-extension"; 1199 | path = "Blindside-watchOS BuildTest Extension.appex"; 1200 | remoteRef = 4C18B19A1BC4E27100CF54F4 /* PBXContainerItemProxy */; 1201 | sourceTree = BUILT_PRODUCTS_DIR; 1202 | }; 1203 | 4C18B19F1BC4E27100CF54F4 /* Cedar.framework */ = { 1204 | isa = PBXReferenceProxy; 1205 | fileType = wrapper.framework; 1206 | path = Cedar.framework; 1207 | remoteRef = 4C18B19E1BC4E27100CF54F4 /* PBXContainerItemProxy */; 1208 | sourceTree = BUILT_PRODUCTS_DIR; 1209 | }; 1210 | 4C18B1A11BC4E27100CF54F4 /* Cedar-iOS Specs.app */ = { 1211 | isa = PBXReferenceProxy; 1212 | fileType = wrapper.application; 1213 | path = "Cedar-iOS Specs.app"; 1214 | remoteRef = 4C18B1A01BC4E27100CF54F4 /* PBXContainerItemProxy */; 1215 | sourceTree = BUILT_PRODUCTS_DIR; 1216 | }; 1217 | 4C18B1A51BC4E27100CF54F4 /* KSDeferred.framework */ = { 1218 | isa = PBXReferenceProxy; 1219 | fileType = wrapper.framework; 1220 | path = KSDeferred.framework; 1221 | remoteRef = 4C18B1A41BC4E27100CF54F4 /* PBXContainerItemProxy */; 1222 | sourceTree = BUILT_PRODUCTS_DIR; 1223 | }; 1224 | 4C18B1A71BC4E27100CF54F4 /* KSDeferred.framework */ = { 1225 | isa = PBXReferenceProxy; 1226 | fileType = wrapper.framework; 1227 | path = KSDeferred.framework; 1228 | remoteRef = 4C18B1A61BC4E27100CF54F4 /* PBXContainerItemProxy */; 1229 | sourceTree = BUILT_PRODUCTS_DIR; 1230 | }; 1231 | 4C833A9918E50DD30011D3C3 /* Cedar.framework */ = { 1232 | isa = PBXReferenceProxy; 1233 | fileType = wrapper.framework; 1234 | path = Cedar.framework; 1235 | remoteRef = 4C833A9818E50DD30011D3C3 /* PBXContainerItemProxy */; 1236 | sourceTree = BUILT_PRODUCTS_DIR; 1237 | }; 1238 | 4C833A9B18E50DD30011D3C3 /* Cedar-OSX Specs */ = { 1239 | isa = PBXReferenceProxy; 1240 | fileType = "compiled.mach-o.executable"; 1241 | path = "Cedar-OSX Specs"; 1242 | remoteRef = 4C833A9A18E50DD30011D3C3 /* PBXContainerItemProxy */; 1243 | sourceTree = BUILT_PRODUCTS_DIR; 1244 | }; 1245 | 4C833A9D18E50DD30011D3C3 /* Cedar-OSX FocusedSpecs */ = { 1246 | isa = PBXReferenceProxy; 1247 | fileType = "compiled.mach-o.executable"; 1248 | path = "Cedar-OSX FocusedSpecs"; 1249 | remoteRef = 4C833A9C18E50DD30011D3C3 /* PBXContainerItemProxy */; 1250 | sourceTree = BUILT_PRODUCTS_DIR; 1251 | }; 1252 | 4C833A9F18E50DD30011D3C3 /* libCedar.a */ = { 1253 | isa = PBXReferenceProxy; 1254 | fileType = archive.ar; 1255 | path = libCedar.a; 1256 | remoteRef = 4C833A9E18E50DD30011D3C3 /* PBXContainerItemProxy */; 1257 | sourceTree = BUILT_PRODUCTS_DIR; 1258 | }; 1259 | 4C833AA118E50DD30011D3C3 /* Cedar-iOS StaticLib Specs.app */ = { 1260 | isa = PBXReferenceProxy; 1261 | fileType = wrapper.application; 1262 | path = "Cedar-iOS StaticLib Specs.app"; 1263 | remoteRef = 4C833AA018E50DD30011D3C3 /* PBXContainerItemProxy */; 1264 | sourceTree = BUILT_PRODUCTS_DIR; 1265 | }; 1266 | 4C833AA318E50DD30011D3C3 /* Cedar-iOS StaticFrameworkSpecs.app */ = { 1267 | isa = PBXReferenceProxy; 1268 | fileType = wrapper.application; 1269 | path = "Cedar-iOS StaticFrameworkSpecs.app"; 1270 | remoteRef = 4C833AA218E50DD30011D3C3 /* PBXContainerItemProxy */; 1271 | sourceTree = BUILT_PRODUCTS_DIR; 1272 | }; 1273 | 4C833AA518E50DD30011D3C3 /* Cedar-iOS HostApp.app */ = { 1274 | isa = PBXReferenceProxy; 1275 | fileType = wrapper.application; 1276 | path = "Cedar-iOS HostApp.app"; 1277 | remoteRef = 4C833AA418E50DD30011D3C3 /* PBXContainerItemProxy */; 1278 | sourceTree = BUILT_PRODUCTS_DIR; 1279 | }; 1280 | 4C833AA918E50DD30011D3C3 /* Cedar-iOS SpecBundle.xctest */ = { 1281 | isa = PBXReferenceProxy; 1282 | fileType = wrapper.cfbundle; 1283 | path = "Cedar-iOS SpecBundle.xctest"; 1284 | remoteRef = 4C833AA818E50DD30011D3C3 /* PBXContainerItemProxy */; 1285 | sourceTree = BUILT_PRODUCTS_DIR; 1286 | }; 1287 | 4CA4826A18E50FF800E524B6 /* Blindside.framework */ = { 1288 | isa = PBXReferenceProxy; 1289 | fileType = wrapper.framework; 1290 | path = Blindside.framework; 1291 | remoteRef = 4CA4826918E50FF800E524B6 /* PBXContainerItemProxy */; 1292 | sourceTree = BUILT_PRODUCTS_DIR; 1293 | }; 1294 | 4CA4826C18E50FF800E524B6 /* Specs */ = { 1295 | isa = PBXReferenceProxy; 1296 | fileType = "compiled.mach-o.executable"; 1297 | path = Specs; 1298 | remoteRef = 4CA4826B18E50FF800E524B6 /* PBXContainerItemProxy */; 1299 | sourceTree = BUILT_PRODUCTS_DIR; 1300 | }; 1301 | 4CA4826E18E50FF800E524B6 /* libBlindside-StaticLib.a */ = { 1302 | isa = PBXReferenceProxy; 1303 | fileType = archive.ar; 1304 | path = "libBlindside-StaticLib.a"; 1305 | remoteRef = 4CA4826D18E50FF800E524B6 /* PBXContainerItemProxy */; 1306 | sourceTree = BUILT_PRODUCTS_DIR; 1307 | }; 1308 | 4CA4827D18E5106800E524B6 /* libDeferred.a */ = { 1309 | isa = PBXReferenceProxy; 1310 | fileType = archive.ar; 1311 | path = libDeferred.a; 1312 | remoteRef = 4CA4827C18E5106800E524B6 /* PBXContainerItemProxy */; 1313 | sourceTree = BUILT_PRODUCTS_DIR; 1314 | }; 1315 | 4CA4827F18E5106800E524B6 /* libDeferred-OSX.a */ = { 1316 | isa = PBXReferenceProxy; 1317 | fileType = archive.ar; 1318 | path = "libDeferred-OSX.a"; 1319 | remoteRef = 4CA4827E18E5106800E524B6 /* PBXContainerItemProxy */; 1320 | sourceTree = BUILT_PRODUCTS_DIR; 1321 | }; 1322 | /* End PBXReferenceProxy section */ 1323 | 1324 | /* Begin PBXResourcesBuildPhase section */ 1325 | 4C1650C718E50CA1000336FD /* Resources */ = { 1326 | isa = PBXResourcesBuildPhase; 1327 | buildActionMask = 2147483647; 1328 | files = ( 1329 | 4C1650DF18E50CA1000336FD /* Images.xcassets in Resources */, 1330 | 4C0B92FF1ACF5D7100DE75AC /* Launch Screen.xib in Resources */, 1331 | ); 1332 | runOnlyForDeploymentPostprocessing = 0; 1333 | }; 1334 | 4C18B1AA1BC4E2CB00CF54F4 /* Resources */ = { 1335 | isa = PBXResourcesBuildPhase; 1336 | buildActionMask = 2147483647; 1337 | files = ( 1338 | 4C18B1C21BC4E31000CF54F4 /* artists.json in Resources */, 1339 | ); 1340 | runOnlyForDeploymentPostprocessing = 0; 1341 | }; 1342 | /* End PBXResourcesBuildPhase section */ 1343 | 1344 | /* Begin PBXSourcesBuildPhase section */ 1345 | 4C1650C518E50CA1000336FD /* Sources */ = { 1346 | isa = PBXSourcesBuildPhase; 1347 | buildActionMask = 2147483647; 1348 | files = ( 1349 | 4C8145C218E5173700FA565A /* InjectorKeys.m in Sources */, 1350 | 4CAB2EA71ACF600B002AB81E /* RequestProvider.m in Sources */, 1351 | 4CAA2CF418E79CEA00488E9B /* ArtistCellPresenter.m in Sources */, 1352 | 4CAA2CF018E79C9B00488E9B /* Artist.m in Sources */, 1353 | 4C8145BC18E5169700FA565A /* ArtistsViewController.m in Sources */, 1354 | 4C8145BE18E5169700FA565A /* UIModule.m in Sources */, 1355 | 4C1650DD18E50CA1000336FD /* AppDelegate.m in Sources */, 1356 | 4CA3C85F18E77BB70082556D /* ArtistsPresenter.m in Sources */, 1357 | 4C1650D918E50CA1000336FD /* main.m in Sources */, 1358 | 4CA3C85B18E77B3B0082556D /* CellPresenterDataSource.m in Sources */, 1359 | 4CA3C86418E77C840082556D /* ArtistsService.m in Sources */, 1360 | 2225F8685C87791451F87892 /* HTTPClient.m in Sources */, 1361 | 2225F7DA142A2DA92BDB35F5 /* JSONClient.m in Sources */, 1362 | 2225FB3AEBA39757263BC8A9 /* NetworkModule.m in Sources */, 1363 | 2225FE5BED01473F71B63378 /* InjectorProvider.m in Sources */, 1364 | 2225FD911CE7FDBA49E61750 /* FoundationModule.m in Sources */, 1365 | 2225FC41AAD3AC205BA2B147 /* ArtistViewController.m in Sources */, 1366 | ); 1367 | runOnlyForDeploymentPostprocessing = 0; 1368 | }; 1369 | 4C18B1A81BC4E2CB00CF54F4 /* Sources */ = { 1370 | isa = PBXSourcesBuildPhase; 1371 | buildActionMask = 2147483647; 1372 | files = ( 1373 | 4C18B1BA1BC4E2F300CF54F4 /* ArtistCellPresenterSpec.mm in Sources */, 1374 | 4C18B1BE1BC4E30800CF54F4 /* ArtistsServiceSpec.mm in Sources */, 1375 | 4C18B1B81BC4E2EA00CF54F4 /* ArtistViewControllerSpec.mm in Sources */, 1376 | 4C18B1BF1BC4E30800CF54F4 /* HTTPClientSpec.mm in Sources */, 1377 | 4C18B1B71BC4E2E700CF54F4 /* ArtistsViewControllerSpec.mm in Sources */, 1378 | 4C18B1BC1BC4E2F900CF54F4 /* CellPresenterDataSourceSpec.mm in Sources */, 1379 | 4C18B1B91BC4E2EF00CF54F4 /* FakeCellPresenterDataSource.m in Sources */, 1380 | 4C18B1C01BC4E30800CF54F4 /* JSONClientSpec.mm in Sources */, 1381 | 4C18B1BB1BC4E2F600CF54F4 /* ArtistsPresenterSpec.mm in Sources */, 1382 | 4C18B1C11BC4E30800CF54F4 /* RequestProviderSpec.mm in Sources */, 1383 | 4C18B1B61BC4E2E300CF54F4 /* AppDelegateSpec.mm in Sources */, 1384 | ); 1385 | runOnlyForDeploymentPostprocessing = 0; 1386 | }; 1387 | /* End PBXSourcesBuildPhase section */ 1388 | 1389 | /* Begin PBXTargetDependency section */ 1390 | 4C18B1B21BC4E2CC00CF54F4 /* PBXTargetDependency */ = { 1391 | isa = PBXTargetDependency; 1392 | target = 4C1650C818E50CA1000336FD /* BestPractices */; 1393 | targetProxy = 4C18B1B11BC4E2CC00CF54F4 /* PBXContainerItemProxy */; 1394 | }; 1395 | 4C18B1C41BC4E3CD00CF54F4 /* PBXTargetDependency */ = { 1396 | isa = PBXTargetDependency; 1397 | name = "Cedar-StaticLib"; 1398 | targetProxy = 4C18B1C31BC4E3CD00CF54F4 /* PBXContainerItemProxy */; 1399 | }; 1400 | 4C18B1C71BC4E42C00CF54F4 /* PBXTargetDependency */ = { 1401 | isa = PBXTargetDependency; 1402 | name = "UIKit+PivotalSpecHelper-StaticLib"; 1403 | targetProxy = 4C18B1C61BC4E42C00CF54F4 /* PBXContainerItemProxy */; 1404 | }; 1405 | 4C18B1C91BC4E43000CF54F4 /* PBXTargetDependency */ = { 1406 | isa = PBXTargetDependency; 1407 | name = "UIKit+PivotalSpecHelperStubs-StaticLib"; 1408 | targetProxy = 4C18B1C81BC4E43000CF54F4 /* PBXContainerItemProxy */; 1409 | }; 1410 | 4CA4827018E5100700E524B6 /* PBXTargetDependency */ = { 1411 | isa = PBXTargetDependency; 1412 | name = "Blindside-StaticLib"; 1413 | targetProxy = 4CA4826F18E5100700E524B6 /* PBXContainerItemProxy */; 1414 | }; 1415 | 4CA4828318E5107700E524B6 /* PBXTargetDependency */ = { 1416 | isa = PBXTargetDependency; 1417 | name = Deferred; 1418 | targetProxy = 4CA4828218E5107700E524B6 /* PBXContainerItemProxy */; 1419 | }; 1420 | /* End PBXTargetDependency section */ 1421 | 1422 | /* Begin XCBuildConfiguration section */ 1423 | 4C1650F318E50CA1000336FD /* Debug */ = { 1424 | isa = XCBuildConfiguration; 1425 | buildSettings = { 1426 | ALWAYS_SEARCH_USER_PATHS = NO; 1427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 1428 | CLANG_CXX_LIBRARY = "libc++"; 1429 | CLANG_ENABLE_MODULES = YES; 1430 | CLANG_ENABLE_OBJC_ARC = YES; 1431 | CLANG_WARN_BOOL_CONVERSION = YES; 1432 | CLANG_WARN_CONSTANT_CONVERSION = YES; 1433 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 1434 | CLANG_WARN_EMPTY_BODY = YES; 1435 | CLANG_WARN_ENUM_CONVERSION = YES; 1436 | CLANG_WARN_INT_CONVERSION = YES; 1437 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1439 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1440 | COPY_PHASE_STRIP = NO; 1441 | ENABLE_TESTABILITY = YES; 1442 | GCC_C_LANGUAGE_STANDARD = gnu99; 1443 | GCC_DYNAMIC_NO_PIC = NO; 1444 | GCC_OPTIMIZATION_LEVEL = 0; 1445 | GCC_PREPROCESSOR_DEFINITIONS = ( 1446 | "DEBUG=1", 1447 | "$(inherited)", 1448 | ); 1449 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 1450 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 1451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1455 | GCC_WARN_UNUSED_FUNCTION = YES; 1456 | GCC_WARN_UNUSED_VARIABLE = YES; 1457 | ONLY_ACTIVE_ARCH = YES; 1458 | OTHER_LDFLAGS = ( 1459 | "-ObjC", 1460 | "-all_load", 1461 | "-lstdc++", 1462 | ); 1463 | SDKROOT = iphoneos; 1464 | USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Externals/blindside/Headers/Public $(PROJECT_DIR)/Externals/deferred/Deferred"; 1465 | }; 1466 | name = Debug; 1467 | }; 1468 | 4C1650F418E50CA1000336FD /* Release */ = { 1469 | isa = XCBuildConfiguration; 1470 | buildSettings = { 1471 | ALWAYS_SEARCH_USER_PATHS = NO; 1472 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 1473 | CLANG_CXX_LIBRARY = "libc++"; 1474 | CLANG_ENABLE_MODULES = YES; 1475 | CLANG_ENABLE_OBJC_ARC = YES; 1476 | CLANG_WARN_BOOL_CONVERSION = YES; 1477 | CLANG_WARN_CONSTANT_CONVERSION = YES; 1478 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 1479 | CLANG_WARN_EMPTY_BODY = YES; 1480 | CLANG_WARN_ENUM_CONVERSION = YES; 1481 | CLANG_WARN_INT_CONVERSION = YES; 1482 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1483 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1484 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1485 | COPY_PHASE_STRIP = YES; 1486 | ENABLE_NS_ASSERTIONS = NO; 1487 | GCC_C_LANGUAGE_STANDARD = gnu99; 1488 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 1489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1493 | GCC_WARN_UNUSED_FUNCTION = YES; 1494 | GCC_WARN_UNUSED_VARIABLE = YES; 1495 | OTHER_LDFLAGS = ( 1496 | "-ObjC", 1497 | "-all_load", 1498 | "-lstdc++", 1499 | ); 1500 | SDKROOT = iphoneos; 1501 | USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Externals/blindside/Headers/Public $(PROJECT_DIR)/Externals/deferred/Deferred"; 1502 | VALIDATE_PRODUCT = YES; 1503 | }; 1504 | name = Release; 1505 | }; 1506 | 4C1650F618E50CA1000336FD /* Debug */ = { 1507 | isa = XCBuildConfiguration; 1508 | buildSettings = { 1509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 1510 | INFOPLIST_FILE = "BestPractices/BestPractices-Info.plist"; 1511 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1512 | PRODUCT_BUNDLE_IDENTIFIER = "me.cbg.${PRODUCT_NAME:rfc1034identifier}"; 1513 | PRODUCT_NAME = "$(TARGET_NAME)"; 1514 | WRAPPER_EXTENSION = app; 1515 | }; 1516 | name = Debug; 1517 | }; 1518 | 4C1650F718E50CA1000336FD /* Release */ = { 1519 | isa = XCBuildConfiguration; 1520 | buildSettings = { 1521 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 1522 | INFOPLIST_FILE = "BestPractices/BestPractices-Info.plist"; 1523 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1524 | PRODUCT_BUNDLE_IDENTIFIER = "me.cbg.${PRODUCT_NAME:rfc1034identifier}"; 1525 | PRODUCT_NAME = "$(TARGET_NAME)"; 1526 | WRAPPER_EXTENSION = app; 1527 | }; 1528 | name = Release; 1529 | }; 1530 | 4C18B1B41BC4E2CC00CF54F4 /* Debug */ = { 1531 | isa = XCBuildConfiguration; 1532 | buildSettings = { 1533 | BUNDLE_LOADER = "$(TEST_HOST)"; 1534 | CLANG_WARN_UNREACHABLE_CODE = YES; 1535 | DEBUG_INFORMATION_FORMAT = dwarf; 1536 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1537 | GCC_NO_COMMON_BLOCKS = YES; 1538 | INFOPLIST_FILE = BestPracticesTests/Info.plist; 1539 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 1540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1541 | MTL_ENABLE_DEBUG_INFO = YES; 1542 | PRODUCT_BUNDLE_IDENTIFIER = me.cbg.BestPracticesTests; 1543 | PRODUCT_NAME = "$(TARGET_NAME)"; 1544 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BestPractices.app/BestPractices"; 1545 | USER_HEADER_SEARCH_PATHS = "$(inherited) $(PROJECT_DIR)/Externals/cedar/Source/Headers/Public/**"; 1546 | }; 1547 | name = Debug; 1548 | }; 1549 | 4C18B1B51BC4E2CC00CF54F4 /* Release */ = { 1550 | isa = XCBuildConfiguration; 1551 | buildSettings = { 1552 | BUNDLE_LOADER = "$(TEST_HOST)"; 1553 | CLANG_WARN_UNREACHABLE_CODE = YES; 1554 | COPY_PHASE_STRIP = NO; 1555 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 1556 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1557 | GCC_NO_COMMON_BLOCKS = YES; 1558 | INFOPLIST_FILE = BestPracticesTests/Info.plist; 1559 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 1560 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1561 | MTL_ENABLE_DEBUG_INFO = NO; 1562 | PRODUCT_BUNDLE_IDENTIFIER = me.cbg.BestPracticesTests; 1563 | PRODUCT_NAME = "$(TARGET_NAME)"; 1564 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BestPractices.app/BestPractices"; 1565 | USER_HEADER_SEARCH_PATHS = "$(inherited) $(PROJECT_DIR)/Externals/cedar/Source/Headers/Public/**"; 1566 | }; 1567 | name = Release; 1568 | }; 1569 | /* End XCBuildConfiguration section */ 1570 | 1571 | /* Begin XCConfigurationList section */ 1572 | 4C1650C418E50CA1000336FD /* Build configuration list for PBXProject "BestPractices" */ = { 1573 | isa = XCConfigurationList; 1574 | buildConfigurations = ( 1575 | 4C1650F318E50CA1000336FD /* Debug */, 1576 | 4C1650F418E50CA1000336FD /* Release */, 1577 | ); 1578 | defaultConfigurationIsVisible = 0; 1579 | defaultConfigurationName = Release; 1580 | }; 1581 | 4C1650F518E50CA1000336FD /* Build configuration list for PBXNativeTarget "BestPractices" */ = { 1582 | isa = XCConfigurationList; 1583 | buildConfigurations = ( 1584 | 4C1650F618E50CA1000336FD /* Debug */, 1585 | 4C1650F718E50CA1000336FD /* Release */, 1586 | ); 1587 | defaultConfigurationIsVisible = 0; 1588 | defaultConfigurationName = Release; 1589 | }; 1590 | 4C18B1B31BC4E2CC00CF54F4 /* Build configuration list for PBXNativeTarget "BestPracticesTests" */ = { 1591 | isa = XCConfigurationList; 1592 | buildConfigurations = ( 1593 | 4C18B1B41BC4E2CC00CF54F4 /* Debug */, 1594 | 4C18B1B51BC4E2CC00CF54F4 /* Release */, 1595 | ); 1596 | defaultConfigurationIsVisible = 0; 1597 | defaultConfigurationName = Release; 1598 | }; 1599 | /* End XCConfigurationList section */ 1600 | }; 1601 | rootObject = 4C1650C118E50CA1000336FD /* Project object */; 1602 | } 1603 | --------------------------------------------------------------------------------