Commits

José Manuel Sánchez Peñarroja  committed 8dfcf5d

Added enumerateDatasource aspect and unit tests. Added font category with a method to get the ctfontref from a uifont. Added bannerviewcontroller for implementing banners

  • Participants
  • Parent commits 9bbe7d5

Comments (0)

Files changed (14)

File Example/Example.xcworkspace/xcuserdata/josanchez.xcuserdatad/UserInterfaceState.xcuserstate

Binary file modified.

File Example/Example.xcworkspace/xcuserdata/josanchez.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

             endingLineNumber = "53">
          </BreakpointContent>
       </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "../bmf/ios/view controllers/BMFBannerViewController.m"
+            timestampString = "425827810.798741"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "44"
+            endingLineNumber = "44"
+            landmarkName = "-viewDidLoad"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
    </Breakpoints>
 </Bucket>

File Example/Example/Example.xcodeproj/project.pbxproj

 		AC82DEDD1869873E00CB335E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AC82DEDB1869873E00CB335E /* InfoPlist.strings */; };
 		AC82DEDF1869873E00CB335E /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AC82DEDE1869873E00CB335E /* ExampleTests.m */; };
 		AC85DA0718FD3DFD00F60102 /* bmfValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AC85DA0618FD3DFD00F60102 /* bmfValueTests.m */; };
+		ACA63AD41961874900247D56 /* bmfEnumerateDataSourceAspectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = ACA63AD31961874900247D56 /* bmfEnumerateDataSourceAspectTests.m */; };
 		ACAEE81E193747760020C42B /* bmfStatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = ACAEE81D193747760020C42B /* bmfStatTests.m */; };
 		ACCFF1491910E65B002BC1FD /* bmfUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = ACCFF1481910E65B002BC1FD /* bmfUtilsTests.m */; };
 		ACD3C2C818EC4D9D002FE462 /* BMFExampleTestConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = ACD3C2C718EC4D9D002FE462 /* BMFExampleTestConfigurator.m */; };
 		AC82DEDE1869873E00CB335E /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = "<group>"; };
 		AC85DA0618FD3DFD00F60102 /* bmfValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bmfValueTests.m; sourceTree = "<group>"; };
 		AC99835E18A4DAEF004AB11B /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
+		ACA63AD31961874900247D56 /* bmfEnumerateDataSourceAspectTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bmfEnumerateDataSourceAspectTests.m; sourceTree = "<group>"; };
 		ACAEE81D193747760020C42B /* bmfStatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bmfStatTests.m; sourceTree = "<group>"; };
 		ACB9E965705442149781C224 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		ACCFF1481910E65B002BC1FD /* bmfUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bmfUtilsTests.m; sourceTree = "<group>"; };
 				AC7BBF3618F6AC0A00CD7BA4 /* bmfEncodingTests.m */,
 				AC4FE88418F8298B00D8E845 /* bmfLoaderTests.m */,
 				AC85DA0618FD3DFD00F60102 /* bmfValueTests.m */,
+				ACA63AD31961874900247D56 /* bmfEnumerateDataSourceAspectTests.m */,
 				AC52FBEE18F42ECF007FA26E /* bmfDataStoreTests.m */,
 				AC472F5E1929E968004FCBEC /* bmfObjectDataStoreTests.m */,
 				AC66CE4F18F2B45000B633C9 /* bmfConditionTests.m */,
 				AC52FBF218F43993007FA26E /* BMFDataStoresModel.xcdatamodeld in Sources */,
 				AC472F5F1929E968004FCBEC /* bmfObjectDataStoreTests.m in Sources */,
 				AC4FE88518F8298B00D8E845 /* bmfLoaderTests.m in Sources */,
+				ACA63AD41961874900247D56 /* bmfEnumerateDataSourceAspectTests.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

File Example/Example/Example/SecondViewController.h

 //  Copyright (c) 2013 José Manuel Sánchez. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+@import UIKit;
 
 @interface SecondViewController : UIViewController
 

File Example/Example/bmfTests/bmfEnumerateDataSourceAspectTests.m

+//
+//  bmfEnumerateDataSourceAspectTests.m
+//  Example
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//  Copyright (c) 2014 José Manuel Sánchez. All rights reserved.
+//
+
+#import <XCTest/XCTest.h>
+#import <Specta/Specta.h>
+#define EXP_SHORTHAND
+#import <Expecta/Expecta.h>
+#import <OCMock/OCMock.h>
+
+#import "BMF.h"
+
+#import "BMFDataSourceProtocol.h"
+#import "BMFEnumerateDataSourceAspect.h"
+#import "BMFArrayDataStore.h"
+
+#import "BMFCompoundDataStore.h"
+
+SpecBegin(EnumerateDataSourceAspect)
+
+describe(@"empty store", ^{
+	
+	it(@"should return error when enumerating forward",^{
+		id<BMFDataReadProtocol> dataStore = [[BMFArrayDataStore alloc] init];
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(id result, NSError *error) {
+			expect(error).toNot.beNil();
+			expect(result).to.beNil();
+		}];
+	});
+	
+	it(@"should return error when enumerating backward",^{
+		id<BMFDataReadProtocol> dataStore = [[BMFArrayDataStore alloc] init];
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		aspect.mode = BMFEnumerateDataSourceAspectModeBackward;
+		[aspect setObject:dataSource];
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(id result, NSError *error) {
+			expect(error).toNot.beNil();
+			expect(result).to.beNil();
+		}];
+	});
+});
+
+describe(@"1 section store", ^{
+	it(@"should correctly enumerate forward",^{
+		BMFArrayDataStore *dataStore = [[BMFArrayDataStore alloc] init];
+		dataStore.items = @[ @1,@2,@3,@4 ];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.mode).to.equal(BMFEnumerateDataSourceAspectModeForward);
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@2);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(2);
+			expect([dataStore itemAt:result]).to.equal(@3);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(3);
+			expect([dataStore itemAt:result]).to.equal(@4);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+	
+	it(@"should correctly enumerate forward",^{
+		BMFArrayDataStore *dataStore = [[BMFArrayDataStore alloc] init];
+		dataStore.items = @[ @1,@2,@3,@4 ];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.mode).to.equal(BMFEnumerateDataSourceAspectModeBackward);
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(3);
+			expect([dataStore itemAt:result]).to.equal(@4);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(2);
+			expect([dataStore itemAt:result]).to.equal(@3);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@2);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+
+});
+
+describe(@"Multiple sections store", ^{
+	it(@"should correctly enumerate forward",^{
+		BMFArrayDataStore *dataStore1 = [[BMFArrayDataStore alloc] init];
+		dataStore1.items = @[ @1,@2 ];
+
+		BMFArrayDataStore *dataStore2 = [[BMFArrayDataStore alloc] init];
+		dataStore2.items = @[ @3 ];
+
+		BMFArrayDataStore *dataStore3 = [[BMFArrayDataStore alloc] init];
+		dataStore3.items = @[ @4, @5  ];
+
+		
+		BMFCompoundDataStore *dataStore = [[BMFCompoundDataStore alloc] initWithStores:@[ dataStore1, dataStore2, dataStore3 ]];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.mode).to.equal(BMFEnumerateDataSourceAspectModeForward);
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@2);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@3);
+			expect(result.section).to.equal(1);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@4);
+			expect(result.section).to.equal(2);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@5);
+			expect(result.section).to.equal(2);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+	
+	it(@"should correctly enumerate bacward",^{
+		BMFArrayDataStore *dataStore1 = [[BMFArrayDataStore alloc] init];
+		dataStore1.items = @[ @1,@2 ];
+		
+		BMFArrayDataStore *dataStore2 = [[BMFArrayDataStore alloc] init];
+		dataStore2.items = @[ @3 ];
+		
+		BMFArrayDataStore *dataStore3 = [[BMFArrayDataStore alloc] init];
+		dataStore3.items = @[ @4, @5  ];
+		
+		
+		BMFCompoundDataStore *dataStore = [[BMFCompoundDataStore alloc] initWithStores:@[ dataStore1, dataStore2, dataStore3 ]];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		aspect.mode = BMFEnumerateDataSourceAspectModeBackward;
+		[aspect setObject:dataSource];
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@5);
+			expect(result.section).to.equal(2);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@4);
+			expect(result.section).to.equal(2);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@3);
+			expect(result.section).to.equal(1);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(1);
+			expect([dataStore itemAt:result]).to.equal(@2);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+});
+
+describe(@"With condition", ^{
+	it(@"shouldn't eumerate forward if the condition is false",^{
+		BMFArrayDataStore *dataStore = [[BMFArrayDataStore alloc] init];
+		dataStore.items = @[ @1,@2,@3,@4 ];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		aspect.condition = [BMFFalseCondition new];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.mode).to.equal(BMFEnumerateDataSourceAspectModeForward);
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+	
+	it(@"shouldn't eumerate backward if the condition is false",^{
+		BMFArrayDataStore *dataStore = [[BMFArrayDataStore alloc] init];
+		dataStore.items = @[ @1,@2,@3,@4 ];
+		
+		id dataSource = [OCMockObject mockForProtocol:@protocol(BMFDataSourceProtocol)];
+		[[[dataSource stub] andReturn:dataStore] dataStore];
+		
+		BMFEnumerateDataSourceAspect *aspect = [[BMFEnumerateDataSourceAspect alloc] init];
+		aspect.mode = BMFEnumerateDataSourceAspectModeBackward;
+		aspect.condition = [BMFFalseCondition new];
+		[aspect setObject:dataSource];
+		
+		expect(aspect.indexPath.row).to.equal(0);
+		expect(aspect.indexPath.section).to.equal(0);
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+		
+		[aspect action:nil completion:^(NSIndexPath *result, NSError *error) {
+			expect(error).to.beNil();
+			expect(result.row).to.equal(0);
+			expect([dataStore itemAt:result]).to.equal(@1);
+			expect(result.section).to.equal(0);
+		}];
+	});
+});
+
+SpecEnd

File bmf/ios/behaviors/BMFTimerViewControllerBehavior.m

 	[self stopTimer];
 }
 
+- (void) setInterval:(NSUInteger)interval {
+	_interval = interval;
+	[self stopTimer];
+	[self startTimer];
+}
+
 - (void) startTimer {
 	if (self.timer) [self stopTimer];
 	self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval target:self selector:@selector(update:) userInfo:nil repeats:YES];

File bmf/ios/view controllers/BMFBannerViewController.h

+//
+//  BMFBannerViewController.h
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import "BMFCollectionViewController.h"
+
+typedef NS_ENUM(NSUInteger, BMFBannerViewControllerScrollDirection) {
+    BMFBannerViewControllerScrollDirectionHorizontal,
+    BMFBannerViewControllerScrollDirectionVertical
+};
+
+@interface BMFBannerViewController : BMFCollectionViewController
+
+/// Time that each item is shown in the banner in seconds. 5 by default
+@property (nonatomic, assign) NSUInteger slideDuration;
+@property (nonatomic, assign) BMFBannerViewControllerScrollDirection scrollDirection;
+
+
+@end

File bmf/ios/view controllers/BMFBannerViewController.m

+//
+//  BMFBannerViewController.m
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import "BMFBannerViewController.h"
+
+#import "BMFCollectionViewDataSource.h"
+#import "BMFTimerViewControllerBehavior.h"
+#import "BMFEnumerateDataSourceAspect.h"
+
+#import "BMF.h"
+
+@interface BMFBannerViewController () <UICollectionViewDelegate>
+
+@property (nonatomic, weak) BMFTimerViewControllerBehavior *timerBehavior;
+
+@end
+
+@implementation BMFBannerViewController
+
+
+- (void) viewDidLoad {
+	[super viewDidLoad];
+	
+	self.scrollDirection = BMFBannerViewControllerScrollDirectionHorizontal;
+	
+	UICollectionViewFlowLayout *flowLayout = [UICollectionViewFlowLayout BMF_cast:self.collectionView.collectionViewLayout];
+	BMFAssertReturn(flowLayout);
+
+	flowLayout.itemSize = self.view.bounds.size;
+	
+	flowLayout.minimumInteritemSpacing = 0;
+	flowLayout.minimumLineSpacing = 0;
+	
+	self.collectionView.delegate = self;
+	
+	_slideDuration = 5;
+	
+	BMFEnumerateDataSourceAspect *enumerateAspect = [BMFEnumerateDataSourceAspect new];
+	[self.dataSource BMF_addAspect:enumerateAspect];
+	
+	self.timerBehavior = [BMFTimerViewControllerBehavior new];
+	self.timerBehavior.interval = _slideDuration;
+	self.timerBehavior.actionBlock = ^(id sender) {
+		[enumerateAspect action:sender completion:^(NSIndexPath *result, NSError *error) {
+			if (!error) {
+				[self.collectionView selectItemAtIndexPath:result animated:YES scrollPosition:UICollectionViewScrollPositionLeft];
+			}
+		}];
+	};
+	[self addBehavior:self.timerBehavior];
+}
+
+- (void) setSlideDuration:(NSUInteger)slideDuration {
+	_slideDuration = slideDuration;
+	
+	self.timerBehavior.interval = _slideDuration;
+}
+
+- (void) setScrollDirection:(BMFBannerViewControllerScrollDirection)scrollDirection {
+	_scrollDirection = scrollDirection;
+	
+	UICollectionViewFlowLayout *flowLayout = [UICollectionViewFlowLayout BMF_cast:self.collectionView.collectionViewLayout];
+	BMFAssertReturn(flowLayout);
+	
+	if (self.scrollDirection==BMFBannerViewControllerScrollDirectionHorizontal)	flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+	else flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
+
+}
+
+#pragma mark UICollectionViewDelegate
+
+- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+	
+	
+}
+
+@end

File bmf/shared/aspects/BMFEnumerateDataSourceAspect.h

+//
+//  BMFEnumerateDataSourceAspect.h
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+#import "BMFTypes.h"
+#import "BMFCondition.h"
+#import "BMFActionableProtocol.h"
+#import "BMFAspect.h"
+
+typedef NS_ENUM(NSUInteger, BMFEnumerateDataSourceAspectMode) {
+    BMFEnumerateDataSourceAspectModeForward,
+    BMFEnumerateDataSourceAspectModeBackward
+};
+
+@interface BMFEnumerateDataSourceAspect : BMFAspect <BMFActionableProtocol>
+
+/// BMFEnumerateDataSourceAspectModeForward by default
+@property (nonatomic, assign) BMFEnumerateDataSourceAspectMode mode;
+
+/// Condition to be met for continuing enumeration. BMFConditionTrue by default
+@property (nonatomic, strong) BMFCondition *condition;
+
+
+@property (nonatomic, readonly) NSIndexPath *indexPath;
+
+/// Returns an indexPath pointing to the next item in the data source.
+- (void) action:(id) input completion:(BMFCompletionBlock) completion;
+
+
+@end

File bmf/shared/aspects/BMFEnumerateDataSourceAspect.m

+//
+//  BMFEnumerateDataSourceAspect.m
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import "BMFEnumerateDataSourceAspect.h"
+
+#import "BMFDataSourceProtocol.h"
+
+#import "BMF.h"
+
+@implementation BMFEnumerateDataSourceAspect
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+		_mode = BMFEnumerateDataSourceAspectModeForward;
+		_condition = [BMFTrueCondition new];
+		_indexPath = [NSIndexPath BMF_indexPathForRow:0 inSection:0];
+    }
+    return self;
+}
+
+- (void) setObject:(id)object {
+	BMFAssertReturn([object conformsToProtocol:@protocol(BMFDataSourceProtocol)]);
+	
+	[super setObject:object];
+}
+
+- (void) action:(id) input completion:(BMFCompletionBlock) completion {
+	
+	id<BMFDataSourceProtocol> dataSource = self.object;
+	id<BMFDataReadProtocol> store = dataSource.dataStore;
+	
+	if ([store numberOfSections]==0 || [store allItems].count==0) {
+		if (completion) completion(nil,[NSError errorWithDomain:@"Data Source aspect" code:BMFErrorData userInfo:@{ NSLocalizedDescriptionKey : BMFLocalized(@"No data in store",nil) }]);
+		return;
+	}
+	
+	if ([_condition evaluate]) {
+		if (_mode==BMFEnumerateDataSourceAspectModeForward) {
+			[self p_enumerateForward:store];
+		}
+		else {
+			[self p_enumerateBackward:store];
+		}
+	}
+		
+	if (completion) completion(_indexPath,nil);
+}
+
+- (BOOL) p_row:(NSInteger)row section:(NSInteger)section insideStore:(id<BMFDataReadProtocol>) store {
+	return ( row>=0 && section>=0 && [store numberOfSections]>section && [store numberOfRowsInSection:section]>row );
+}
+
+
+- (void) p_enumerateForward:(id<BMFDataReadProtocol>) store {
+	NSInteger row = _indexPath.BMF_row;
+	NSInteger section = _indexPath.BMF_section;
+
+	row++;
+	if (![self p_row:row section:section insideStore:store]) {
+		section++;
+		row = 0;
+		if ([store numberOfSections]<=section) section = 0;
+		
+		/// This should never happen
+		BMFAssertReturn([self p_row:row section:section insideStore:store]);
+	}
+	
+
+	_indexPath = [NSIndexPath BMF_indexPathForRow:row inSection:section];
+}
+
+
+- (void) p_enumerateBackward:(id<BMFDataReadProtocol>) store {
+	NSInteger row = _indexPath.BMF_row;
+	NSInteger section = _indexPath.BMF_section;
+	
+	row--;
+	if (row<0) {
+		section--;
+		if (section<0) section = [store numberOfSections]-1;
+
+		row = [store numberOfRowsInSection:section]-1;
+		
+		/// This should never happen
+		BMFAssertReturn([self p_row:row section:section insideStore:store]);
+	}
+	
+	_indexPath = [NSIndexPath BMF_indexPathForRow:row inSection:section];
+}
+
+@end

File bmf/shared/categories/BMFIXFont+BMF.h

+//
+//  BMFIXFont+BMF.h
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import "BMFTypes.h"
+#import <CoreText/CoreText.h>
+
+@interface BMFIXFont (BMF)
+
+- (CTFontRef) BMF_ctFont;
+
+@end

File bmf/shared/categories/BMFIXFont+BMF.m

+//
+//  BMFIXFont+BMF.m
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import "BMFIXFont+BMF.h"
+
+@implementation BMFIXFont (BMF)
+
+- (CTFontRef) BMF_ctFont {
+	return CTFontCreateWithName((CFStringRef)self.fontDescriptor.postscriptName, self.pointSize, NULL);
+}
+
+@end

File bmf/shared/model/BMFBannerItemImageProtocol.h

+//
+//  BMFBannerItemImageProtocol.h
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+@import UIKit;
+
+#import "BMFTypes.h"
+
+@protocol BMFBannerItemImageProtocol <NSObject>
+
+@property (nonatomic, copy) NSString *imageUrl;
+@property (nonatomic, strong) BMFIXImage *image;
+
+- (void) load:(BMFCompletionBlock) completionBlock;
+
+@end

File bmf/shared/model/BMFBannerItemProtocol.h

+//
+//  BMFBannerItemProtocol.h
+//  Pods
+//
+//  Created by Jose Manuel Sánchez Peñarroja on 30/06/14.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+@protocol BMFBannerItemProtocol <NSObject>
+
+
+
+@end