├── BKDeltaCalculatorExample ├── CollectionViewController.h ├── TableViewController.h ├── AppDelegate.h ├── main.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── AppDelegate.m ├── Info.plist ├── TableViewController.m ├── Base.lproj │ └── LaunchScreen.xib └── CollectionViewController.m ├── BKDeltaCalculator.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── BKDeltaCalculator.xcscheme │ │ └── BKDeltaCalculatorExample.xcscheme └── project.pbxproj ├── BKDeltaCalculator ├── BKDelta_Internal.h ├── BKDelta.h ├── BKDeltaCalculator.h ├── BKDeltaCalculator.m └── BKDelta.m ├── BKDeltaCalculatorExampleTests ├── Info.plist └── BKDeltaCalculatorExampleTests.m ├── BKDeltaCalculator.podspec ├── LICENSE ├── README.md └── .gitignore /BKDeltaCalculatorExample/CollectionViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import 4 | 5 | @interface CollectionViewController : UICollectionViewController 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/TableViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import 4 | 5 | @interface TableViewController : UITableViewController 6 | 7 | 8 | @end 9 | 10 | -------------------------------------------------------------------------------- /BKDeltaCalculator.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import 4 | 5 | @interface AppDelegate : UIResponder 6 | 7 | @property (strong, nonatomic) UIWindow *window; 8 | 9 | 10 | @end 11 | 12 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/main.m: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import 4 | #import "AppDelegate.h" 5 | 6 | int main(int argc, char * argv[]) { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /BKDeltaCalculator/BKDelta_Internal.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014-present Andrew Toulouse. 2 | 3 | #import "BKDelta.h" 4 | 5 | @interface BKDelta () 6 | 7 | + (instancetype)deltaWithAddedIndices:(NSIndexSet *)addedIndices 8 | removedIndices:(NSIndexSet *)removedIndices 9 | movedIndexPairs:(NSArray *)movedIndexPairs 10 | unchangedIndices:(NSIndexSet *)unchangedIndices; 11 | 12 | - (instancetype)initWithAddedIndices:(NSIndexSet *)addedIndices 13 | removedIndices:(NSIndexSet *)removedIndices 14 | movedIndexPairs:(NSArray *)movedIndexPairs 15 | unchangedIndices:(NSIndexSet *)unchangedIndices; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /BKDeltaCalculator/BKDelta.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014-present Andrew Toulouse. 2 | 3 | #import 4 | #import 5 | 6 | @interface BKDelta : NSObject 7 | 8 | @property (nonatomic, copy, readonly) NSIndexSet *addedIndices; 9 | @property (nonatomic, copy, readonly) NSIndexSet *removedIndices; 10 | @property (nonatomic, copy, readonly) NSArray *movedIndexPairs; 11 | @property (nonatomic, copy, readonly) NSIndexSet *unchangedIndices; 12 | 13 | - (void)applyUpdatesToTableView:(UITableView *)tableView inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)rowAnimation; 14 | - (void)applyUpdatesToCollectionView:(UICollectionView *)collectionView inSection:(NSUInteger)section; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /BKDeltaCalculatorExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | se.atoulou.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import "AppDelegate.h" 4 | 5 | #import "CollectionViewController.h" 6 | #import "TableViewController.h" 7 | 8 | @interface AppDelegate () 9 | 10 | @end 11 | 12 | @implementation AppDelegate 13 | 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 17 | // self.window.rootViewController = [[TableViewController alloc] initWithStyle:UITableViewStylePlain]; 18 | 19 | UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; 20 | flowLayout.itemSize = CGSizeMake(40, 40); 21 | self.window.rootViewController = [[CollectionViewController alloc] initWithCollectionViewLayout:flowLayout]; 22 | 23 | [self.window makeKeyAndVisible]; 24 | return YES; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExampleTests/BKDeltaCalculatorExampleTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import 4 | #import 5 | 6 | @interface BKDeltaCalculatorExampleTests : XCTestCase 7 | 8 | @end 9 | 10 | @implementation BKDeltaCalculatorExampleTests 11 | 12 | - (void)setUp { 13 | [super setUp]; 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | - (void)tearDown { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | [super tearDown]; 20 | } 21 | 22 | - (void)testExample { 23 | // This is an example of a functional test case. 24 | XCTAssert(YES, @"Pass"); 25 | } 26 | 27 | - (void)testPerformanceExample { 28 | // This is an example of a performance test case. 29 | [self measureBlock:^{ 30 | // Put the code you want to measure the time of here. 31 | }]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /BKDeltaCalculator.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "BKDeltaCalculator" 3 | s.version = "1.1.2" 4 | s.summary = "Lightweight Objective-C library to transform a pair of collections into sets of changes" 5 | s.description = "Lightweight Objective-C library to transform a pair of collections into sets of changes, primarily for use in dynamically-updated table and collection views" 6 | s.homepage = "https://github.com/Basket/BKDeltaCalculator" 7 | s.license = 'MIT' 8 | s.author = { "Andrew Toulouse" => "andrew@atoulou.se" } 9 | s.source = { :git => "https://github.com/Basket/BKDeltaCalculator.git", :tag => s.version.to_s } 10 | 11 | s.platform = :ios, '7.0' 12 | s.requires_arc = true 13 | 14 | s.source_files = 'BKDeltaCalculator/*.{h,m}' 15 | s.public_header_files = 'BKDeltaCalculator/BKDelta.h', 16 | 'BKDeltaCalculator/BKDeltaCalculator.h' 17 | s.frameworks = 'Foundation' 18 | end 19 | -------------------------------------------------------------------------------- /BKDeltaCalculator/BKDeltaCalculator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014-present 650 Industries. 2 | // Copyright 2014-present Andrew Toulouse. 3 | 4 | #import 5 | 6 | @class BKDelta; 7 | 8 | typedef BOOL (^delta_calculator_equality_test_t)(id a, id b); 9 | 10 | extern const delta_calculator_equality_test_t BKDeltaCalculatorStrictEqualityTest; 11 | 12 | @interface BKDeltaCalculator : NSObject 13 | 14 | + (instancetype)defaultCalculator; 15 | 16 | + (instancetype)deltaCalculatorWithEqualityTest:(delta_calculator_equality_test_t)equalityTest; 17 | 18 | - (instancetype)initWithEqualityTest:(delta_calculator_equality_test_t)equalityTest; 19 | 20 | /** 21 | Resolve differences between two versions of an array. 22 | 23 | @param oldArray the array representing the "old" version of the array 24 | @param newArray the array representing the "new" version of the array. 25 | @return A delta object containing NSIndexSets representing added, moved, removed, and unchanged elements. 26 | */ 27 | - (BKDelta *)deltaFromOldArray:(NSArray *)oldArray toNewArray:(NSArray *)newArray; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 650 Industries, Inc. 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | se.atoulou.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BKDeltaCalculator 2 | Lightweight Objective-C library to transform a pair of collections into sets of changes. These changes can be applied to UITableView and UICollectionView instances in batched updates, providing a more declarative way to update your views. 3 | 4 | 5 | ## Installation 6 | 7 | BKDeltaCalculator is available through [CocoaPods](http://cocoapods.org/). To install it, simply add the following line to your Podfile: 8 | ```ruby 9 | pod "BKDeltaCalculator" 10 | ``` 11 | 12 | ## Usage 13 | 14 | BKDeltaCalculator compares two arrays and computes the delta between them, represented by a BKDelta object. The two arrays may contain the old and new models to display in a table view or collection view, for example. 15 | ```objc 16 | BKDeltaCalculator *calculator = [BKDeltaCalculator defaultCalculator]; 17 | BKDelta *delta = [calculator deltaFromOldArray:oldArray toNewArray:newArray]; 18 | ``` 19 | 20 | ### Table and Collection Views 21 | 22 | You can apply BKDelta to a UITableView or UICollectionView when the old array represents the currently displayed cells and the new array represents the cells to display next. Used a batched update to smoothly animate the cells. 23 | ```objc 24 | // With a UITableView: 25 | [tableView beginUpdates]; 26 | BKDelta *delta = [[BKDeltaCalculator defaultCalculator] deltaFromOldArray:_items toNewArray:newItems]; 27 | [delta applyUpdatesToTableView:tableView inSection:0 withRowAnimation:UITableViewRowAnimationFade]; 28 | _items = [newItems copy]; 29 | [tableView endUpdates]; 30 | 31 | // With a UICollectionView: 32 | [collectionView performBatchUpdates:^{ 33 | [delta applyUpdatesToCollectionView:collectionView inSection:0]; 34 | _items = [newItems copy]; 35 | } completion:nil]; 36 | ``` 37 | 38 | ### Equality Checks 39 | 40 | By default, BKDeltaCalculator compares items in the two arrays using strict equality checks that compare object identities. You can also provide a custom comparator: 41 | ```objc 42 | BKDeltaCalculator calculator = [BKDeltaCalculator deltaCalculatorWithEqualityTest:^(id a, id b) { 43 | return (a == b) || [a isEqual:b]; 44 | }]; 45 | ``` 46 | -------------------------------------------------------------------------------- /BKDeltaCalculator.xcodeproj/xcshareddata/xcschemes/BKDeltaCalculator.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 51 | 52 | 54 | 55 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/TableViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import "TableViewController.h" 4 | 5 | #import "BKDelta.h" 6 | #import "BKDeltaCalculator.h" 7 | 8 | @interface TableViewCell : UITableViewCell 9 | @property (nonatomic, assign) NSUInteger number; 10 | @end 11 | @implementation TableViewCell 12 | @end 13 | 14 | @implementation TableViewController { 15 | NSArray *_items; 16 | } 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | NSMutableArray *mutableItems = [NSMutableArray array]; 22 | for (NSUInteger i = 0; i < 3; i++) { 23 | [mutableItems addObject:@(i)]; 24 | } 25 | _items = [mutableItems copy]; 26 | 27 | [self.tableView registerClass:[TableViewCell class] forCellReuseIdentifier:NSStringFromClass([TableViewCell class])]; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 33 | { 34 | return _items.count; 35 | } 36 | 37 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 38 | { 39 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([TableViewCell class]) forIndexPath:indexPath]; 40 | cell.textLabel.text = [_items[indexPath.row] description]; 41 | return cell; 42 | } 43 | 44 | #pragma mark - 45 | 46 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 47 | { 48 | // Shuffle 49 | NSMutableArray *newItems = [_items mutableCopy]; 50 | NSUInteger count = newItems.count; 51 | for (NSUInteger i = 0; i < count; ++i) { 52 | NSInteger remainingCount = newItems.count - i; 53 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 54 | [newItems exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex]; 55 | } 56 | 57 | // Delete randomly 58 | for (NSUInteger i = 0; i < 2; ++i) { 59 | NSInteger remainingCount = newItems.count - i; 60 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 61 | [newItems exchangeObjectAtIndex:newItems.count - 1 withObjectAtIndex:exchangeIndex]; 62 | NSLog(@"REMOVED %@", [newItems lastObject]); 63 | [newItems removeLastObject]; 64 | } 65 | 66 | // Add randomly 67 | for (NSUInteger i = 0; i < 3; ++i) { 68 | NSNumber *max = [[newItems sortedArrayUsingSelector: @selector(compare:)] lastObject]; 69 | [newItems addObject:@([max unsignedIntegerValue] + 1)]; 70 | NSLog(@"ADDED %@", [newItems lastObject]); 71 | NSInteger remainingCount = newItems.count - i; 72 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 73 | [newItems exchangeObjectAtIndex:newItems.count - 1 withObjectAtIndex:exchangeIndex]; 74 | } 75 | 76 | [tableView beginUpdates]; 77 | BKDelta *delta = [[BKDeltaCalculator defaultCalculator] deltaFromOldArray:_items toNewArray:newItems]; 78 | [delta applyUpdatesToTableView:tableView inSection:0 withRowAnimation:UITableViewRowAnimationFade]; 79 | _items = [newItems copy]; 80 | [tableView endUpdates]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /BKDeltaCalculator/BKDeltaCalculator.m: -------------------------------------------------------------------------------- 1 | // Copyright 2014-present 650 Industries. 2 | // Copyright 2014-present Andrew Toulouse. 3 | 4 | #import "BKDeltaCalculator.h" 5 | 6 | #import "BKDelta.h" 7 | #import "BKDelta_Internal.h" 8 | 9 | const delta_calculator_equality_test_t BKDeltaCalculatorStrictEqualityTest = ^BOOL(id a, id b) { 10 | return a == b; 11 | }; 12 | 13 | @implementation BKDeltaCalculator { 14 | delta_calculator_equality_test_t _equalityTest; 15 | } 16 | 17 | + (instancetype)defaultCalculator 18 | { 19 | static BKDeltaCalculator *INSTANCE; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | INSTANCE = [[BKDeltaCalculator alloc] init]; 23 | }); 24 | 25 | return INSTANCE; 26 | } 27 | 28 | + (instancetype)deltaCalculatorWithEqualityTest:(delta_calculator_equality_test_t)equalityTest 29 | { 30 | return [[BKDeltaCalculator alloc] initWithEqualityTest:equalityTest]; 31 | } 32 | 33 | - (instancetype)init 34 | { 35 | return [self initWithEqualityTest:BKDeltaCalculatorStrictEqualityTest]; 36 | } 37 | 38 | - (instancetype)initWithEqualityTest:(delta_calculator_equality_test_t)equalityTest 39 | { 40 | if (self = [super init]) { 41 | _equalityTest = equalityTest; 42 | } 43 | return self; 44 | } 45 | 46 | - (BKDelta *)deltaFromOldArray:(NSArray *)oldArray toNewArray:(NSArray *)newArray 47 | { 48 | // Index set for objects... 49 | NSMutableIndexSet *unchangedIndices = [NSMutableIndexSet indexSet]; // ...with identical positions 50 | NSMutableArray *movedIndices = [NSMutableArray array]; // ...which moved, in pairs [old index, new index] 51 | NSMutableIndexSet *addedNewIndices = [NSMutableIndexSet indexSet]; // ...which were added, new index 52 | NSMutableIndexSet *removedOldIndices = [NSMutableIndexSet indexSet]; // ...which were deleted, old index 53 | 54 | // Unchanged 55 | for (NSUInteger index = 0; index < oldArray.count; index++) { 56 | if (index >= newArray.count) { // Bounds check. No unchanged indices possible when out of range 57 | break; 58 | } 59 | if (_equalityTest(oldArray[index], newArray[index])) { 60 | [unchangedIndices addIndex:index]; 61 | } 62 | } 63 | 64 | // Moved and added 65 | for (NSUInteger newIndex = 0; newIndex < newArray.count; newIndex++) { 66 | if ([unchangedIndices containsIndex:newIndex]) { 67 | continue; 68 | } 69 | 70 | id newItem = newArray[newIndex]; 71 | NSUInteger oldIndex = [oldArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 72 | return _equalityTest(obj, newItem); 73 | }]; 74 | if (!oldArray || oldIndex == NSNotFound) { 75 | [addedNewIndices addIndex:newIndex]; 76 | } else { 77 | [movedIndices addObject:@[@(oldIndex), @(newIndex)]]; 78 | } 79 | } 80 | 81 | // Removed 82 | for (NSUInteger oldIndex = 0; oldIndex < oldArray.count; oldIndex++) { 83 | id oldItem = oldArray[oldIndex]; 84 | NSUInteger newIndex = [newArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 85 | return _equalityTest(obj, oldItem); 86 | }]; 87 | if (newIndex == NSNotFound) { 88 | [removedOldIndices addIndex:oldIndex]; 89 | } 90 | } 91 | 92 | return [BKDelta deltaWithAddedIndices:[addedNewIndices copy] 93 | removedIndices:[removedOldIndices copy] 94 | movedIndexPairs:[movedIndices copy] 95 | unchangedIndices:[unchangedIndices copy]]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ######################### 2 | # .gitignore file for Xcode4 / OS X Source projects 3 | # 4 | # Version 2.0 5 | # For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects 6 | # 7 | # 2013 updates: 8 | # - fixed the broken "save personal Schemes" 9 | # 10 | # NB: if you are storing "built" products, this WILL NOT WORK, 11 | # and you should use a different .gitignore (or none at all) 12 | # This file is for SOURCE projects, where there are many extra 13 | # files that we want to exclude 14 | # 15 | ######################### 16 | 17 | ##### 18 | # OS X temporary files that should never be committed 19 | 20 | .DS_Store 21 | *.swp 22 | *.lock 23 | profile 24 | 25 | 26 | #### 27 | # Xcode temporary files that should never be committed 28 | # 29 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 30 | 31 | *~.nib 32 | 33 | 34 | #### 35 | # Xcode build files - 36 | # 37 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 38 | 39 | DerivedData/ 40 | 41 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 42 | 43 | build/ 44 | 45 | 46 | ##### 47 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 48 | # 49 | # This is complicated: 50 | # 51 | # SOMETIMES you need to put this file in version control. 52 | # Apple designed it poorly - if you use "custom executables", they are 53 | # saved in this file. 54 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 55 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 56 | 57 | *.pbxuser 58 | *.mode1v3 59 | *.mode2v3 60 | *.perspectivev3 61 | # NB: also, whitelist the default ones, some projects need to use these 62 | !default.pbxuser 63 | !default.mode1v3 64 | !default.mode2v3 65 | !default.perspectivev3 66 | 67 | 68 | #### 69 | # Xcode 4 - semi-personal settings 70 | # 71 | # 72 | # OPTION 1: --------------------------------- 73 | # throw away ALL personal settings (including custom schemes! 74 | # - unless they are "shared") 75 | # 76 | # NB: this is exclusive with OPTION 2 below 77 | xcuserdata 78 | 79 | # OPTION 2: --------------------------------- 80 | # get rid of ALL personal settings, but KEEP SOME OF THEM 81 | # - NB: you must manually uncomment the bits you want to keep 82 | # 83 | # NB: this is exclusive with OPTION 1 above 84 | # 85 | #xcuserdata/**/* 86 | 87 | # (requires option 2 above): Personal Schemes 88 | # 89 | #!xcuserdata/**/xcschemes/* 90 | 91 | #### 92 | # XCode 4 workspaces - more detailed 93 | # 94 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 95 | # 96 | # Workspace layout is quite spammy. For reference: 97 | # 98 | # /(root)/ 99 | # /(project-name).xcodeproj/ 100 | # project.pbxproj 101 | # /project.xcworkspace/ 102 | # contents.xcworkspacedata 103 | # /xcuserdata/ 104 | # /(your name)/xcuserdatad/ 105 | # UserInterfaceState.xcuserstate 106 | # /xcsshareddata/ 107 | # /xcschemes/ 108 | # (shared scheme name).xcscheme 109 | # /xcuserdata/ 110 | # /(your name)/xcuserdatad/ 111 | # (private scheme).xcscheme 112 | # xcschememanagement.plist 113 | # 114 | # 115 | 116 | #### 117 | # Xcode 4 - Deprecated classes 118 | # 119 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 120 | # 121 | # We're using source-control, so this is a "feature" that we do not want! 122 | 123 | *.moved-aside 124 | 125 | 126 | #### 127 | # UNKNOWN: recommended by others, but I can't discover what these files are 128 | # 129 | # ...none. Everything is now explained. -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /BKDeltaCalculatorExample/CollectionViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2015-present Andrew Toulouse. 2 | 3 | #import "CollectionViewController.h" 4 | 5 | #import "BKDelta.h" 6 | #import "BKDeltaCalculator.h" 7 | 8 | @interface CollectionViewCell : UICollectionViewCell 9 | @property (nonatomic, assign) NSUInteger number; 10 | @end 11 | @implementation CollectionViewCell 12 | @end 13 | 14 | @implementation CollectionViewController { 15 | NSArray *_items; 16 | } 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | NSMutableArray *mutableItems = [NSMutableArray array]; 22 | for (NSUInteger i = 0; i < 3; i++) { 23 | [mutableItems addObject:@(i)]; 24 | } 25 | _items = [mutableItems copy]; 26 | 27 | [self.collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([CollectionViewCell class])]; 28 | } 29 | 30 | #pragma mark 31 | 32 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { 33 | return 1; 34 | } 35 | 36 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 37 | return _items.count; 38 | } 39 | 40 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 41 | CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([CollectionViewCell class]) forIndexPath:indexPath]; 42 | cell.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.5]; 43 | UILabel *label = (UILabel *)[cell.contentView viewWithTag:1337]; 44 | if (!label) { 45 | label = [[UILabel alloc] init]; 46 | label.textColor = [UIColor whiteColor]; 47 | label.tag = 1337; 48 | [cell.contentView addSubview:label]; 49 | } 50 | label.text = [_items[indexPath.row] description]; 51 | [label sizeToFit]; 52 | label.center = CGPointMake(CGRectGetMidX(cell.bounds), CGRectGetMidY(cell.bounds)); 53 | return cell; 54 | } 55 | 56 | #pragma mark 57 | 58 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { 59 | 60 | // Shuffle 61 | NSMutableArray *newItems = [_items mutableCopy]; 62 | NSUInteger count = newItems.count; 63 | for (NSUInteger i = 0; i < count; ++i) { 64 | NSInteger remainingCount = newItems.count - i; 65 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 66 | [newItems exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex]; 67 | } 68 | 69 | // Delete randomly 70 | for (NSUInteger i = 0; i < 2; ++i) { 71 | NSInteger remainingCount = newItems.count - i; 72 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 73 | [newItems exchangeObjectAtIndex:newItems.count - 1 withObjectAtIndex:exchangeIndex]; 74 | NSLog(@"REMOVED %@", [newItems lastObject]); 75 | [newItems removeLastObject]; 76 | } 77 | 78 | // Add randomly 79 | for (NSUInteger i = 0; i < 3; ++i) { 80 | NSNumber *max = [[newItems sortedArrayUsingSelector: @selector(compare:)] lastObject]; 81 | [newItems addObject:@([max unsignedIntegerValue] + 1)]; 82 | NSLog(@"ADDED %@", [newItems lastObject]); 83 | NSInteger remainingCount = newItems.count - i; 84 | NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount); 85 | [newItems exchangeObjectAtIndex:newItems.count - 1 withObjectAtIndex:exchangeIndex]; 86 | } 87 | 88 | BKDelta *delta = [[BKDeltaCalculator defaultCalculator] deltaFromOldArray:_items toNewArray:newItems]; 89 | [collectionView performBatchUpdates:^{ 90 | [delta applyUpdatesToCollectionView:collectionView inSection:0]; 91 | _items = [newItems copy]; 92 | } completion:nil]; 93 | 94 | return YES; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /BKDeltaCalculator/BKDelta.m: -------------------------------------------------------------------------------- 1 | // Copyright 2014-present Andrew Toulouse. 2 | 3 | #import "BKDelta.h" 4 | 5 | @implementation BKDelta 6 | 7 | + (instancetype)deltaWithAddedIndices:(NSIndexSet *)addedIndices 8 | removedIndices:(NSIndexSet *)removedIndices 9 | movedIndexPairs:(NSArray *)movedIndexPairs 10 | unchangedIndices:(NSIndexSet *)unchangedIndices 11 | { 12 | return [[self alloc] initWithAddedIndices:addedIndices 13 | removedIndices:removedIndices 14 | movedIndexPairs:movedIndexPairs 15 | unchangedIndices:unchangedIndices]; 16 | } 17 | 18 | - (instancetype)initWithAddedIndices:(NSIndexSet *)addedIndices 19 | removedIndices:(NSIndexSet *)removedIndices 20 | movedIndexPairs:(NSArray *)movedIndexPairs 21 | unchangedIndices:(NSIndexSet *)unchangedIndices 22 | { 23 | if (self = [super init]) { 24 | _addedIndices = [addedIndices copy]; 25 | _removedIndices = [removedIndices copy]; 26 | _movedIndexPairs = [movedIndexPairs copy]; 27 | _unchangedIndices = [unchangedIndices copy]; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)applyUpdatesToTableView:(UITableView *)tableView inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)rowAnimation 33 | { 34 | NSMutableArray *removedIndexPaths = [NSMutableArray arrayWithCapacity:_removedIndices.count]; 35 | [_removedIndices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 36 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:section]; 37 | [removedIndexPaths addObject:indexPath]; 38 | }]; 39 | 40 | [tableView deleteRowsAtIndexPaths:removedIndexPaths withRowAnimation:rowAnimation]; 41 | 42 | NSMutableArray *addedIndexPaths = [NSMutableArray arrayWithCapacity:_addedIndices.count]; 43 | [_addedIndices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 44 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:section]; 45 | [addedIndexPaths addObject:indexPath]; 46 | }]; 47 | 48 | [tableView insertRowsAtIndexPaths:addedIndexPaths withRowAnimation:rowAnimation]; 49 | 50 | [_movedIndexPairs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 51 | NSNumber *fromIndex = [obj objectAtIndex:0], *toIndex = [obj objectAtIndex:1]; 52 | NSIndexPath *fromIndexPath = [NSIndexPath indexPathForRow:[fromIndex unsignedIntegerValue] inSection:section]; 53 | NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow:[toIndex unsignedIntegerValue] inSection:section]; 54 | [tableView moveRowAtIndexPath:fromIndexPath toIndexPath:toIndexPath]; 55 | }]; 56 | } 57 | 58 | - (void)applyUpdatesToCollectionView:(UICollectionView *)collectionView inSection:(NSUInteger)section 59 | { 60 | NSMutableArray *removedIndexPaths = [NSMutableArray arrayWithCapacity:_removedIndices.count]; 61 | [_removedIndices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 62 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx inSection:section]; 63 | [removedIndexPaths addObject:indexPath]; 64 | }]; 65 | 66 | [collectionView deleteItemsAtIndexPaths:removedIndexPaths]; 67 | 68 | NSMutableArray *addedIndexPaths = [NSMutableArray arrayWithCapacity:_addedIndices.count]; 69 | [_addedIndices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 70 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx inSection:section]; 71 | [addedIndexPaths addObject:indexPath]; 72 | }]; 73 | 74 | [collectionView insertItemsAtIndexPaths:addedIndexPaths]; 75 | 76 | [_movedIndexPairs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 77 | NSNumber *fromIndex = [obj objectAtIndex:0], *toIndex = [obj objectAtIndex:1]; 78 | NSIndexPath *fromIndexPath = [NSIndexPath indexPathForRow:[fromIndex unsignedIntegerValue] inSection:section]; 79 | NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow:[toIndex unsignedIntegerValue] inSection:section]; 80 | [collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath]; 81 | }]; 82 | } 83 | @end 84 | -------------------------------------------------------------------------------- /BKDeltaCalculator.xcodeproj/xcshareddata/xcschemes/BKDeltaCalculatorExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /BKDeltaCalculator.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6B168AF819ABBCD20040751B /* BKDeltaCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B168AF719ABBCD20040751B /* BKDeltaCalculator.m */; }; 11 | 6BB9564619ABC52100CBD3BB /* BKDelta.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BB9564519ABC52100CBD3BB /* BKDelta.m */; }; 12 | 6BD118341A8DE48B0069B52B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD118331A8DE48B0069B52B /* main.m */; }; 13 | 6BD118371A8DE48B0069B52B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD118361A8DE48B0069B52B /* AppDelegate.m */; }; 14 | 6BD1183A1A8DE48B0069B52B /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD118391A8DE48B0069B52B /* TableViewController.m */; }; 15 | 6BD1183F1A8DE48B0069B52B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BD1183E1A8DE48B0069B52B /* Images.xcassets */; }; 16 | 6BD118421A8DE48B0069B52B /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6BD118401A8DE48B0069B52B /* LaunchScreen.xib */; }; 17 | 6BD1184E1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD1184D1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.m */; }; 18 | 6BD118581A8DF0F70069B52B /* BKDelta.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6BB9564419ABC52100CBD3BB /* BKDelta.h */; }; 19 | 6BD1185C1A8DF1C40069B52B /* libBKDeltaCalculator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6BEE09EA19870A1800D73B41 /* libBKDeltaCalculator.a */; }; 20 | 6BD1185F1A8DF6BD0069B52B /* CollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD1185E1A8DF6BD0069B52B /* CollectionViewController.m */; }; 21 | 6BEE09EE19870A1800D73B41 /* BKDeltaCalculator.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6BEE09ED19870A1800D73B41 /* BKDeltaCalculator.h */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 6BD118481A8DE48B0069B52B /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = 6BEE09E219870A1800D73B41 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 6BD1182E1A8DE48B0069B52B; 30 | remoteInfo = BKDeltaCalculatorExample; 31 | }; 32 | 6BD1185A1A8DF1120069B52B /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 6BEE09E219870A1800D73B41 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 6BEE09E919870A1800D73B41; 37 | remoteInfo = BKDeltaCalculator; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | 6BEE09E819870A1800D73B41 /* CopyFiles */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = "include/$(PRODUCT_NAME)"; 46 | dstSubfolderSpec = 16; 47 | files = ( 48 | 6BD118581A8DF0F70069B52B /* BKDelta.h in CopyFiles */, 49 | 6BEE09EE19870A1800D73B41 /* BKDeltaCalculator.h in CopyFiles */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | 6B168AF719ABBCD20040751B /* BKDeltaCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BKDeltaCalculator.m; sourceTree = ""; }; 57 | 6BB9564419ABC52100CBD3BB /* BKDelta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BKDelta.h; sourceTree = ""; }; 58 | 6BB9564519ABC52100CBD3BB /* BKDelta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BKDelta.m; sourceTree = ""; }; 59 | 6BB9564719ABC6AC00CBD3BB /* BKDelta_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BKDelta_Internal.h; sourceTree = ""; }; 60 | 6BD1182F1A8DE48B0069B52B /* BKDeltaCalculatorExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BKDeltaCalculatorExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 6BD118321A8DE48B0069B52B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 6BD118331A8DE48B0069B52B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 63 | 6BD118351A8DE48B0069B52B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 64 | 6BD118361A8DE48B0069B52B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 65 | 6BD118381A8DE48B0069B52B /* TableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; }; 66 | 6BD118391A8DE48B0069B52B /* TableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; }; 67 | 6BD1183E1A8DE48B0069B52B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 68 | 6BD118411A8DE48B0069B52B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 69 | 6BD118471A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BKDeltaCalculatorExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 6BD1184C1A8DE48B0069B52B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | 6BD1184D1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BKDeltaCalculatorExampleTests.m; sourceTree = ""; }; 72 | 6BD1185D1A8DF6BD0069B52B /* CollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionViewController.h; sourceTree = ""; }; 73 | 6BD1185E1A8DF6BD0069B52B /* CollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionViewController.m; sourceTree = ""; }; 74 | 6BEE09EA19870A1800D73B41 /* libBKDeltaCalculator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBKDeltaCalculator.a; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 6BEE09ED19870A1800D73B41 /* BKDeltaCalculator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BKDeltaCalculator.h; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 6BD1182C1A8DE48B0069B52B /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 6BD1185C1A8DF1C40069B52B /* libBKDeltaCalculator.a in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | 6BD118441A8DE48B0069B52B /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | 6BEE09E719870A1800D73B41 /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXFrameworksBuildPhase section */ 102 | 103 | /* Begin PBXGroup section */ 104 | 6BD118301A8DE48B0069B52B /* BKDeltaCalculatorExample */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 6BD118351A8DE48B0069B52B /* AppDelegate.h */, 108 | 6BD118361A8DE48B0069B52B /* AppDelegate.m */, 109 | 6BD1185D1A8DF6BD0069B52B /* CollectionViewController.h */, 110 | 6BD1185E1A8DF6BD0069B52B /* CollectionViewController.m */, 111 | 6BD1183E1A8DE48B0069B52B /* Images.xcassets */, 112 | 6BD118401A8DE48B0069B52B /* LaunchScreen.xib */, 113 | 6BD118311A8DE48B0069B52B /* Supporting Files */, 114 | 6BD118381A8DE48B0069B52B /* TableViewController.h */, 115 | 6BD118391A8DE48B0069B52B /* TableViewController.m */, 116 | ); 117 | path = BKDeltaCalculatorExample; 118 | sourceTree = ""; 119 | }; 120 | 6BD118311A8DE48B0069B52B /* Supporting Files */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 6BD118321A8DE48B0069B52B /* Info.plist */, 124 | 6BD118331A8DE48B0069B52B /* main.m */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | 6BD1184A1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 6BD1184D1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.m */, 133 | 6BD1184B1A8DE48B0069B52B /* Supporting Files */, 134 | ); 135 | path = BKDeltaCalculatorExampleTests; 136 | sourceTree = ""; 137 | }; 138 | 6BD1184B1A8DE48B0069B52B /* Supporting Files */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 6BD1184C1A8DE48B0069B52B /* Info.plist */, 142 | ); 143 | name = "Supporting Files"; 144 | sourceTree = ""; 145 | }; 146 | 6BEE09E119870A1800D73B41 = { 147 | isa = PBXGroup; 148 | children = ( 149 | 6BEE09EC19870A1800D73B41 /* BKDeltaCalculator */, 150 | 6BD118301A8DE48B0069B52B /* BKDeltaCalculatorExample */, 151 | 6BD1184A1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests */, 152 | 6BEE09EB19870A1800D73B41 /* Products */, 153 | ); 154 | sourceTree = ""; 155 | }; 156 | 6BEE09EB19870A1800D73B41 /* Products */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 6BEE09EA19870A1800D73B41 /* libBKDeltaCalculator.a */, 160 | 6BD1182F1A8DE48B0069B52B /* BKDeltaCalculatorExample.app */, 161 | 6BD118471A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.xctest */, 162 | ); 163 | name = Products; 164 | sourceTree = ""; 165 | }; 166 | 6BEE09EC19870A1800D73B41 /* BKDeltaCalculator */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 6BB9564719ABC6AC00CBD3BB /* BKDelta_Internal.h */, 170 | 6BB9564419ABC52100CBD3BB /* BKDelta.h */, 171 | 6BB9564519ABC52100CBD3BB /* BKDelta.m */, 172 | 6BEE09ED19870A1800D73B41 /* BKDeltaCalculator.h */, 173 | 6B168AF719ABBCD20040751B /* BKDeltaCalculator.m */, 174 | ); 175 | path = BKDeltaCalculator; 176 | sourceTree = ""; 177 | }; 178 | /* End PBXGroup section */ 179 | 180 | /* Begin PBXNativeTarget section */ 181 | 6BD1182E1A8DE48B0069B52B /* BKDeltaCalculatorExample */ = { 182 | isa = PBXNativeTarget; 183 | buildConfigurationList = 6BD118531A8DE48B0069B52B /* Build configuration list for PBXNativeTarget "BKDeltaCalculatorExample" */; 184 | buildPhases = ( 185 | 6BD1182B1A8DE48B0069B52B /* Sources */, 186 | 6BD1182C1A8DE48B0069B52B /* Frameworks */, 187 | 6BD1182D1A8DE48B0069B52B /* Resources */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | 6BD1185B1A8DF1120069B52B /* PBXTargetDependency */, 193 | ); 194 | name = BKDeltaCalculatorExample; 195 | productName = BKDeltaCalculatorExample; 196 | productReference = 6BD1182F1A8DE48B0069B52B /* BKDeltaCalculatorExample.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | 6BD118461A8DE48B0069B52B /* BKDeltaCalculatorExampleTests */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 6BD118541A8DE48B0069B52B /* Build configuration list for PBXNativeTarget "BKDeltaCalculatorExampleTests" */; 202 | buildPhases = ( 203 | 6BD118431A8DE48B0069B52B /* Sources */, 204 | 6BD118441A8DE48B0069B52B /* Frameworks */, 205 | 6BD118451A8DE48B0069B52B /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | 6BD118491A8DE48B0069B52B /* PBXTargetDependency */, 211 | ); 212 | name = BKDeltaCalculatorExampleTests; 213 | productName = BKDeltaCalculatorExampleTests; 214 | productReference = 6BD118471A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.xctest */; 215 | productType = "com.apple.product-type.bundle.unit-test"; 216 | }; 217 | 6BEE09E919870A1800D73B41 /* BKDeltaCalculator */ = { 218 | isa = PBXNativeTarget; 219 | buildConfigurationList = 6BEE09FE19870A1900D73B41 /* Build configuration list for PBXNativeTarget "BKDeltaCalculator" */; 220 | buildPhases = ( 221 | 6BEE09E619870A1800D73B41 /* Sources */, 222 | 6BEE09E719870A1800D73B41 /* Frameworks */, 223 | 6BEE09E819870A1800D73B41 /* CopyFiles */, 224 | ); 225 | buildRules = ( 226 | ); 227 | dependencies = ( 228 | ); 229 | name = BKDeltaCalculator; 230 | productName = BKDeltaCalculator; 231 | productReference = 6BEE09EA19870A1800D73B41 /* libBKDeltaCalculator.a */; 232 | productType = "com.apple.product-type.library.static"; 233 | }; 234 | /* End PBXNativeTarget section */ 235 | 236 | /* Begin PBXProject section */ 237 | 6BEE09E219870A1800D73B41 /* Project object */ = { 238 | isa = PBXProject; 239 | attributes = { 240 | LastUpgradeCheck = 0600; 241 | ORGANIZATIONNAME = "650 Industries, Inc."; 242 | TargetAttributes = { 243 | 6BD1182E1A8DE48B0069B52B = { 244 | CreatedOnToolsVersion = 6.1.1; 245 | }; 246 | 6BD118461A8DE48B0069B52B = { 247 | CreatedOnToolsVersion = 6.1.1; 248 | TestTargetID = 6BD1182E1A8DE48B0069B52B; 249 | }; 250 | 6BEE09E919870A1800D73B41 = { 251 | CreatedOnToolsVersion = 6.0; 252 | }; 253 | }; 254 | }; 255 | buildConfigurationList = 6BEE09E519870A1800D73B41 /* Build configuration list for PBXProject "BKDeltaCalculator" */; 256 | compatibilityVersion = "Xcode 3.2"; 257 | developmentRegion = English; 258 | hasScannedForEncodings = 0; 259 | knownRegions = ( 260 | en, 261 | Base, 262 | ); 263 | mainGroup = 6BEE09E119870A1800D73B41; 264 | productRefGroup = 6BEE09EB19870A1800D73B41 /* Products */; 265 | projectDirPath = ""; 266 | projectRoot = ""; 267 | targets = ( 268 | 6BEE09E919870A1800D73B41 /* BKDeltaCalculator */, 269 | 6BD1182E1A8DE48B0069B52B /* BKDeltaCalculatorExample */, 270 | 6BD118461A8DE48B0069B52B /* BKDeltaCalculatorExampleTests */, 271 | ); 272 | }; 273 | /* End PBXProject section */ 274 | 275 | /* Begin PBXResourcesBuildPhase section */ 276 | 6BD1182D1A8DE48B0069B52B /* Resources */ = { 277 | isa = PBXResourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 6BD118421A8DE48B0069B52B /* LaunchScreen.xib in Resources */, 281 | 6BD1183F1A8DE48B0069B52B /* Images.xcassets in Resources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | 6BD118451A8DE48B0069B52B /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | /* End PBXResourcesBuildPhase section */ 293 | 294 | /* Begin PBXSourcesBuildPhase section */ 295 | 6BD1182B1A8DE48B0069B52B /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 6BD1185F1A8DF6BD0069B52B /* CollectionViewController.m in Sources */, 300 | 6BD1183A1A8DE48B0069B52B /* TableViewController.m in Sources */, 301 | 6BD118371A8DE48B0069B52B /* AppDelegate.m in Sources */, 302 | 6BD118341A8DE48B0069B52B /* main.m in Sources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | 6BD118431A8DE48B0069B52B /* Sources */ = { 307 | isa = PBXSourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 6BD1184E1A8DE48B0069B52B /* BKDeltaCalculatorExampleTests.m in Sources */, 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | 6BEE09E619870A1800D73B41 /* Sources */ = { 315 | isa = PBXSourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | 6BB9564619ABC52100CBD3BB /* BKDelta.m in Sources */, 319 | 6B168AF819ABBCD20040751B /* BKDeltaCalculator.m in Sources */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXSourcesBuildPhase section */ 324 | 325 | /* Begin PBXTargetDependency section */ 326 | 6BD118491A8DE48B0069B52B /* PBXTargetDependency */ = { 327 | isa = PBXTargetDependency; 328 | target = 6BD1182E1A8DE48B0069B52B /* BKDeltaCalculatorExample */; 329 | targetProxy = 6BD118481A8DE48B0069B52B /* PBXContainerItemProxy */; 330 | }; 331 | 6BD1185B1A8DF1120069B52B /* PBXTargetDependency */ = { 332 | isa = PBXTargetDependency; 333 | target = 6BEE09E919870A1800D73B41 /* BKDeltaCalculator */; 334 | targetProxy = 6BD1185A1A8DF1120069B52B /* PBXContainerItemProxy */; 335 | }; 336 | /* End PBXTargetDependency section */ 337 | 338 | /* Begin PBXVariantGroup section */ 339 | 6BD118401A8DE48B0069B52B /* LaunchScreen.xib */ = { 340 | isa = PBXVariantGroup; 341 | children = ( 342 | 6BD118411A8DE48B0069B52B /* Base */, 343 | ); 344 | name = LaunchScreen.xib; 345 | sourceTree = ""; 346 | }; 347 | /* End PBXVariantGroup section */ 348 | 349 | /* Begin XCBuildConfiguration section */ 350 | 6BD1184F1A8DE48B0069B52B /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 354 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 355 | GCC_PREPROCESSOR_DEFINITIONS = ( 356 | "DEBUG=1", 357 | "$(inherited)", 358 | ); 359 | INFOPLIST_FILE = BKDeltaCalculatorExample/Info.plist; 360 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 361 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 362 | PRODUCT_NAME = "$(TARGET_NAME)"; 363 | }; 364 | name = Debug; 365 | }; 366 | 6BD118501A8DE48B0069B52B /* Release */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 370 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 371 | INFOPLIST_FILE = BKDeltaCalculatorExample/Info.plist; 372 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 373 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | }; 376 | name = Release; 377 | }; 378 | 6BD118511A8DE48B0069B52B /* Debug */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | BUNDLE_LOADER = "$(TEST_HOST)"; 382 | FRAMEWORK_SEARCH_PATHS = ( 383 | "$(SDKROOT)/Developer/Library/Frameworks", 384 | "$(inherited)", 385 | ); 386 | GCC_PREPROCESSOR_DEFINITIONS = ( 387 | "DEBUG=1", 388 | "$(inherited)", 389 | ); 390 | INFOPLIST_FILE = BKDeltaCalculatorExampleTests/Info.plist; 391 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 393 | PRODUCT_NAME = "$(TARGET_NAME)"; 394 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BKDeltaCalculatorExample.app/BKDeltaCalculatorExample"; 395 | }; 396 | name = Debug; 397 | }; 398 | 6BD118521A8DE48B0069B52B /* Release */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | BUNDLE_LOADER = "$(TEST_HOST)"; 402 | FRAMEWORK_SEARCH_PATHS = ( 403 | "$(SDKROOT)/Developer/Library/Frameworks", 404 | "$(inherited)", 405 | ); 406 | INFOPLIST_FILE = BKDeltaCalculatorExampleTests/Info.plist; 407 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 408 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 409 | PRODUCT_NAME = "$(TARGET_NAME)"; 410 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BKDeltaCalculatorExample.app/BKDeltaCalculatorExample"; 411 | }; 412 | name = Release; 413 | }; 414 | 6BEE09FC19870A1900D73B41 /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ALWAYS_SEARCH_USER_PATHS = NO; 418 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 419 | CLANG_CXX_LIBRARY = "libc++"; 420 | CLANG_ENABLE_MODULES = YES; 421 | CLANG_ENABLE_OBJC_ARC = YES; 422 | CLANG_WARN_BOOL_CONVERSION = YES; 423 | CLANG_WARN_CONSTANT_CONVERSION = YES; 424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 425 | CLANG_WARN_EMPTY_BODY = YES; 426 | CLANG_WARN_ENUM_CONVERSION = YES; 427 | CLANG_WARN_INT_CONVERSION = YES; 428 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | COPY_PHASE_STRIP = NO; 432 | ENABLE_STRICT_OBJC_MSGSEND = YES; 433 | GCC_C_LANGUAGE_STANDARD = gnu99; 434 | GCC_DYNAMIC_NO_PIC = NO; 435 | GCC_OPTIMIZATION_LEVEL = 0; 436 | GCC_PREPROCESSOR_DEFINITIONS = ( 437 | "DEBUG=1", 438 | "$(inherited)", 439 | ); 440 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 441 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 442 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 443 | GCC_WARN_UNDECLARED_SELECTOR = YES; 444 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 445 | GCC_WARN_UNUSED_FUNCTION = YES; 446 | GCC_WARN_UNUSED_VARIABLE = YES; 447 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 448 | MTL_ENABLE_DEBUG_INFO = YES; 449 | ONLY_ACTIVE_ARCH = YES; 450 | SDKROOT = iphoneos; 451 | }; 452 | name = Debug; 453 | }; 454 | 6BEE09FD19870A1900D73B41 /* Release */ = { 455 | isa = XCBuildConfiguration; 456 | buildSettings = { 457 | ALWAYS_SEARCH_USER_PATHS = NO; 458 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 459 | CLANG_CXX_LIBRARY = "libc++"; 460 | CLANG_ENABLE_MODULES = YES; 461 | CLANG_ENABLE_OBJC_ARC = YES; 462 | CLANG_WARN_BOOL_CONVERSION = YES; 463 | CLANG_WARN_CONSTANT_CONVERSION = YES; 464 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 465 | CLANG_WARN_EMPTY_BODY = YES; 466 | CLANG_WARN_ENUM_CONVERSION = YES; 467 | CLANG_WARN_INT_CONVERSION = YES; 468 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 469 | CLANG_WARN_UNREACHABLE_CODE = YES; 470 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 471 | COPY_PHASE_STRIP = YES; 472 | ENABLE_NS_ASSERTIONS = NO; 473 | ENABLE_STRICT_OBJC_MSGSEND = YES; 474 | GCC_C_LANGUAGE_STANDARD = gnu99; 475 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 476 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 477 | GCC_WARN_UNDECLARED_SELECTOR = YES; 478 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 479 | GCC_WARN_UNUSED_FUNCTION = YES; 480 | GCC_WARN_UNUSED_VARIABLE = YES; 481 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 482 | MTL_ENABLE_DEBUG_INFO = NO; 483 | SDKROOT = iphoneos; 484 | VALIDATE_PRODUCT = YES; 485 | }; 486 | name = Release; 487 | }; 488 | 6BEE09FF19870A1900D73B41 /* Debug */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | OTHER_LDFLAGS = "-ObjC"; 492 | PRODUCT_NAME = "$(TARGET_NAME)"; 493 | SKIP_INSTALL = YES; 494 | }; 495 | name = Debug; 496 | }; 497 | 6BEE0A0019870A1900D73B41 /* Release */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | OTHER_LDFLAGS = "-ObjC"; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | SKIP_INSTALL = YES; 503 | }; 504 | name = Release; 505 | }; 506 | /* End XCBuildConfiguration section */ 507 | 508 | /* Begin XCConfigurationList section */ 509 | 6BD118531A8DE48B0069B52B /* Build configuration list for PBXNativeTarget "BKDeltaCalculatorExample" */ = { 510 | isa = XCConfigurationList; 511 | buildConfigurations = ( 512 | 6BD1184F1A8DE48B0069B52B /* Debug */, 513 | 6BD118501A8DE48B0069B52B /* Release */, 514 | ); 515 | defaultConfigurationIsVisible = 0; 516 | defaultConfigurationName = Release; 517 | }; 518 | 6BD118541A8DE48B0069B52B /* Build configuration list for PBXNativeTarget "BKDeltaCalculatorExampleTests" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | 6BD118511A8DE48B0069B52B /* Debug */, 522 | 6BD118521A8DE48B0069B52B /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | 6BEE09E519870A1800D73B41 /* Build configuration list for PBXProject "BKDeltaCalculator" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | 6BEE09FC19870A1900D73B41 /* Debug */, 531 | 6BEE09FD19870A1900D73B41 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | 6BEE09FE19870A1900D73B41 /* Build configuration list for PBXNativeTarget "BKDeltaCalculator" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | 6BEE09FF19870A1900D73B41 /* Debug */, 540 | 6BEE0A0019870A1900D73B41 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | /* End XCConfigurationList section */ 546 | }; 547 | rootObject = 6BEE09E219870A1800D73B41 /* Project object */; 548 | } 549 | --------------------------------------------------------------------------------