├── Changelog.md ├── DemoApp ├── DemoApp-Info.plist ├── DemoApp-Prefix.pch ├── NXAppDelegate.h ├── NXAppDelegate.m ├── NXViewController.h ├── NXViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── NXViewController.xib └── main.m ├── LICENSE ├── Libraries ├── OCMock.framework │ ├── Headers │ ├── OCMock │ ├── Resources │ └── Versions │ │ ├── A │ │ ├── Headers │ │ │ ├── NSNotificationCenter+OCMAdditions.h │ │ │ ├── OCMArg.h │ │ │ ├── OCMConstraint.h │ │ │ ├── OCMock.h │ │ │ ├── OCMockObject.h │ │ │ └── OCMockRecorder.h │ │ ├── OCMock │ │ └── Resources │ │ │ ├── Info.plist │ │ │ └── en.lproj │ │ │ └── InfoPlist.strings │ │ └── Current └── SVPullToRefresh │ ├── SVPullToRefresh.h │ └── SVPullToRefresh.m ├── Readme.md ├── UITableView+NXEmptyView.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── UITableView+NXEmptyView ├── UITableView+NXEmptyView-Info.plist ├── UITableView+NXEmptyView-Prefix.pch ├── UITableView+NXEmptyView.h ├── UITableView+NXEmptyView.m └── en.lproj │ └── InfoPlist.strings ├── UITableView+NXEmptyViewTests ├── UITableView+NXEmptyViewTests-Info.plist ├── UITableView_NXEmptyViewTests.h ├── UITableView_NXEmptyViewTests.m └── en.lproj │ └── InfoPlist.strings └── UITableView-NXEmptyView.podspec /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # v0.1.4 4 | - adding the empty view only once (so layouting only runs once), 5 | using `hidden` property now to trigger visibility 6 | 7 | # v0.1.3 8 | - preventing the empty view from hiding the table header view 9 | 10 | # v0.1.2 11 | - fixing issue #1 (support for pull to refresh) 12 | - adding an option to hide the seperator lines when the empty view is shown (great for transparent empty views!) 13 | 14 | # v0.1.1 15 | - fixed a bug where the empty wouldn't be resized when the table view resizes while the empty view is shown - b0c6de5 16 | - added an extension to the `UITableViewDataSource` protocol to bypass the showing of the empty view - 09564aa 17 | 18 | # v0.1.0 19 | 20 | - Initial release 21 | -------------------------------------------------------------------------------- /DemoApp/DemoApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.nxtbgthng.${PRODUCT_NAME:rfc1034identifier} 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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /DemoApp/DemoApp-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DemoApp' target in the 'DemoApp' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /DemoApp/NXAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXAppDelegate.h 3 | // DemoApp 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class NXViewController; 12 | 13 | @interface NXAppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) NXViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /DemoApp/NXAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // NXAppDelegate.m 3 | // DemoApp 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import "NXAppDelegate.h" 10 | 11 | #import "NXViewController.h" 12 | 13 | @implementation NXAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.viewController = [[NXViewController alloc] initWithNibName:@"NXViewController" bundle:nil]; 20 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 21 | [self.window makeKeyAndVisible]; 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application 26 | { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | - (void)applicationDidEnterBackground:(UIApplication *)application 32 | { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application 38 | { 39 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | - (void)applicationDidBecomeActive:(UIApplication *)application 43 | { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | - (void)applicationWillTerminate:(UIApplication *)application 48 | { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /DemoApp/NXViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXViewController.h 3 | // DemoApp 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NXViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DemoApp/NXViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NXViewController.m 3 | // DemoApp 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "SVPullToRefresh.h" 12 | 13 | #import "NXViewController.h" 14 | 15 | 16 | @interface NXViewController () 17 | 18 | @property (nonatomic, retain) NSArray *items; 19 | @end 20 | 21 | @implementation NXViewController 22 | 23 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; 24 | { 25 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 26 | if (self) { 27 | self.items = [NSArray arrayWithObjects:@"0", @"1", nil]; 28 | UIBarButtonItem *addItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 29 | target:self action:@selector(add:)]; 30 | UIBarButtonItem *removeItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemUndo 31 | target:self action:@selector(remove:)]; 32 | self.toolbarItems = [NSArray arrayWithObjects:addItem, removeItem, nil]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)viewDidLoad; 38 | { 39 | [super viewDidLoad]; 40 | self.tableView.nxEV_hideSeparatorLinesWhenShowingEmptyView = YES; 41 | 42 | Class refreshControlClass = NSClassFromString(@"UIRefreshControl"); 43 | if (refreshControlClass) { 44 | id refreshControl = [[refreshControlClass alloc] init]; 45 | 46 | [refreshControl addTarget:self 47 | action:@selector(refresh:) 48 | forControlEvents:UIControlEventValueChanged]; 49 | 50 | [self setRefreshControl:refreshControl]; 51 | } else { 52 | __block id blockSelf = self; 53 | [self.tableView addPullToRefreshWithActionHandler:^{ 54 | [blockSelf refresh:nil]; 55 | }]; 56 | } 57 | } 58 | 59 | - (void)viewDidAppear:(BOOL)animated; 60 | { 61 | [super viewDidAppear:animated]; 62 | self.navigationController.toolbarHidden = NO; 63 | } 64 | 65 | 66 | #pragma mark Actions 67 | 68 | - (IBAction)add:(id)sender; 69 | { 70 | self.items = [self.items arrayByAddingObject:[NSString stringWithFormat:@"%d", self.items.count]]; 71 | } 72 | 73 | - (IBAction)remove:(id)sender 74 | { 75 | NSInteger length = fmaxf((NSInteger)self.items.count - 1, 0); 76 | self.items = [self.items subarrayWithRange:NSMakeRange(0, length)]; 77 | } 78 | 79 | - (IBAction)refresh:(id)sender 80 | { 81 | if ([self respondsToSelector:@selector(refreshControl)]) { 82 | [self.refreshControl endRefreshing]; 83 | } 84 | 85 | if ([self.tableView respondsToSelector:@selector(pullToRefreshView)]) { 86 | [self.tableView.pullToRefreshView stopAnimating]; 87 | } 88 | 89 | if (self.items.count == 0) { 90 | [self add:nil]; 91 | } 92 | } 93 | 94 | 95 | #pragma mark The DataSource 96 | 97 | - (void)setItems:(NSArray *)items; 98 | { 99 | _items = items; 100 | [self.tableView reloadData]; 101 | } 102 | 103 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 104 | { 105 | return self.items.count; 106 | } 107 | 108 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 109 | { 110 | NSString *identifier = @"xx"; 111 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 112 | if (!cell) { 113 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 114 | } 115 | 116 | cell.textLabel.text = [self.items objectAtIndex:indexPath.row]; 117 | return cell; 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /DemoApp/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /DemoApp/en.lproj/NXViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 12C60 6 | 2843 7 | 1187.34 8 | 625.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1929 12 | 13 | 14 | IBProxyObject 15 | IBUILabel 16 | IBUITableView 17 | IBUIView 18 | 19 | 20 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 21 | 22 | 23 | PluginDependencyRecalculationVersion 24 | 25 | 26 | 27 | 28 | IBFilesOwner 29 | IBCocoaTouchFramework 30 | 31 | 32 | IBFirstResponder 33 | IBCocoaTouchFramework 34 | 35 | 36 | 37 | 274 38 | 39 | {320, 460} 40 | 41 | 42 | _NS:10 43 | 44 | 3 45 | MQA 46 | 47 | NO 48 | YES 49 | NO 50 | IBCocoaTouchFramework 51 | YES 52 | 1 53 | 0 54 | YES 55 | 44 56 | 22 57 | 22 58 | 59 | 60 | 61 | 292 62 | 63 | 64 | 65 | 290 66 | {{10, 140}, {300, 37}} 67 | 68 | 69 | 70 | _NS:9 71 | NO 72 | YES 73 | 7 74 | NO 75 | IBCocoaTouchFramework 76 | No Items 77 | 78 | 1 79 | MCAwIDAAA 80 | darkTextColor 81 | 82 | 83 | 0 84 | 10 85 | 1 86 | 87 | 2 88 | 31 89 | 90 | 91 | Helvetica-Bold 92 | 31 93 | 16 94 | 95 | NO 96 | 97 | 98 | 99 | 264 100 | {{10, 300}, {300, 63}} 101 | 102 | 103 | _NS:9 104 | NO 105 | YES 106 | 7 107 | NO 108 | IBCocoaTouchFramework 109 | VGhlcmUncyBub3RoaW5nIHRvIHNob3cgaW4gdGhlIHRhYmxlIHZpZXcsIHNvIGhlcmUncyB0aGUgZW1w 110 | dHkgdmlldy4gWW91IGNhbiBmaW5kIGl0IGluIE5YVmlld0NvbnRyb2xsZXIueGliCg 111 | 112 | 113 | 0 114 | 10 115 | 0 116 | 1 117 | 0 118 | 119 | 1 120 | 17 121 | 122 | 123 | Helvetica 124 | 17 125 | 16 126 | 127 | NO 128 | 300 129 | 130 | 131 | {320, 460} 132 | 133 | 134 | 135 | _NS:9 136 | 137 | 3 138 | MCAwAA 139 | 140 | IBCocoaTouchFramework 141 | 142 | 143 | 144 | 145 | 146 | 147 | view 148 | 149 | 150 | 151 | 17 152 | 153 | 154 | 155 | nxEV_emptyView 156 | 157 | 158 | 159 | 16 160 | 161 | 162 | 163 | dataSource 164 | 165 | 166 | 167 | 18 168 | 169 | 170 | 171 | delegate 172 | 173 | 174 | 175 | 19 176 | 177 | 178 | 179 | 180 | 181 | 0 182 | 183 | 184 | 185 | 186 | 187 | -1 188 | 189 | 190 | File's Owner 191 | 192 | 193 | -2 194 | 195 | 196 | 197 | 198 | 13 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 14 208 | 209 | 210 | 211 | 212 | 15 213 | 214 | 215 | 216 | 217 | 9 218 | 219 | 220 | 221 | 222 | 223 | 224 | NXViewController 225 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 226 | UIResponder 227 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 228 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 229 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 230 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 231 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 232 | 233 | 234 | 235 | 236 | 237 | 19 238 | 239 | 240 | 241 | 242 | NXViewController 243 | UITableViewController 244 | 245 | id 246 | id 247 | id 248 | 249 | 250 | 251 | add: 252 | id 253 | 254 | 255 | refresh: 256 | id 257 | 258 | 259 | remove: 260 | id 261 | 262 | 263 | 264 | IBProjectSource 265 | ./Classes/NXViewController.h 266 | 267 | 268 | 269 | UITableView 270 | 271 | nxEV_emptyView 272 | UIView 273 | 274 | 275 | nxEV_emptyView 276 | 277 | nxEV_emptyView 278 | UIView 279 | 280 | 281 | 282 | IBProjectSource 283 | ./Classes/UITableView.h 284 | 285 | 286 | 287 | 288 | 0 289 | IBCocoaTouchFramework 290 | 291 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 292 | 293 | 294 | YES 295 | 3 296 | 1929 297 | 298 | 299 | -------------------------------------------------------------------------------- /DemoApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DemoApp 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NXAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([NXAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, nxtbgthng GmbH 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nxtbgthng GmbH nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL nxtbgthng GmbH BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /Libraries/OCMock.framework/OCMock: -------------------------------------------------------------------------------- 1 | Versions/Current/OCMock -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/NSNotificationCenter+OCMAdditions.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2009 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @class OCMockObserver; 9 | 10 | 11 | @interface NSNotificationCenter(OCMAdditions) 12 | 13 | - (void)addMockObserver:(OCMockObserver *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/OCMArg.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2009-2013 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMArg : NSObject 9 | 10 | // constraining arguments 11 | 12 | + (id)any; 13 | + (SEL)anySelector; 14 | + (void *)anyPointer; 15 | + (id __autoreleasing *)anyObjectRef; 16 | + (id)isNil; 17 | + (id)isNotNil; 18 | + (id)isNotEqual:(id)value; 19 | + (id)checkWithSelector:(SEL)selector onObject:(id)anObject; 20 | #if NS_BLOCKS_AVAILABLE 21 | + (id)checkWithBlock:(BOOL (^)(id obj))block; 22 | #endif 23 | 24 | // manipulating arguments 25 | 26 | + (id *)setTo:(id)value; 27 | + (void *)setToValue:(NSValue *)value; 28 | 29 | // internal use only 30 | 31 | + (id)resolveSpecialValues:(NSValue *)value; 32 | 33 | @end 34 | 35 | #define OCMOCK_ANY [OCMArg any] 36 | 37 | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) 38 | #define OCMOCK_VALUE(variable) \ 39 | ({ __typeof__(variable) __v = (variable); [NSValue value:&__v withObjCType:@encode(__typeof__(__v))]; }) 40 | #else 41 | #define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof__(variable))] 42 | #endif 43 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/OCMConstraint.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2007-2010 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | 9 | @interface OCMConstraint : NSObject 10 | 11 | + (id)constraint; 12 | - (BOOL)evaluate:(id)value; 13 | 14 | // if you are looking for any, isNil, etc, they have moved to OCMArg 15 | 16 | // try to use [OCMArg checkWith...] instead of the constraintWith... methods below 17 | 18 | + (id)constraintWithSelector:(SEL)aSelector onObject:(id)anObject; 19 | + (id)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue; 20 | 21 | 22 | @end 23 | 24 | @interface OCMAnyConstraint : OCMConstraint 25 | @end 26 | 27 | @interface OCMIsNilConstraint : OCMConstraint 28 | @end 29 | 30 | @interface OCMIsNotNilConstraint : OCMConstraint 31 | @end 32 | 33 | @interface OCMIsNotEqualConstraint : OCMConstraint 34 | { 35 | @public 36 | id testValue; 37 | } 38 | 39 | @end 40 | 41 | @interface OCMInvocationConstraint : OCMConstraint 42 | { 43 | @public 44 | NSInvocation *invocation; 45 | } 46 | 47 | @end 48 | 49 | #if NS_BLOCKS_AVAILABLE 50 | 51 | @interface OCMBlockConstraint : OCMConstraint 52 | { 53 | BOOL (^block)(id); 54 | } 55 | 56 | - (id)initWithConstraintBlock:(BOOL (^)(id))block; 57 | 58 | @end 59 | 60 | #endif 61 | 62 | 63 | #define CONSTRAINT(aSelector) [OCMConstraint constraintWithSelector:aSelector onObject:self] 64 | #define CONSTRAINTV(aSelector, aValue) [OCMConstraint constraintWithSelector:aSelector onObject:self withValue:(aValue)] 65 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/OCMock.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/OCMockObject.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMockObject : NSProxy 9 | { 10 | BOOL isNice; 11 | BOOL expectationOrderMatters; 12 | NSMutableArray *recorders; 13 | NSMutableArray *expectations; 14 | NSMutableArray *rejections; 15 | NSMutableArray *exceptions; 16 | } 17 | 18 | + (id)mockForClass:(Class)aClass; 19 | + (id)mockForProtocol:(Protocol *)aProtocol; 20 | + (id)partialMockForObject:(NSObject *)anObject; 21 | 22 | + (id)niceMockForClass:(Class)aClass; 23 | + (id)niceMockForProtocol:(Protocol *)aProtocol; 24 | 25 | + (id)observerMock; 26 | 27 | - (id)init; 28 | 29 | - (void)setExpectationOrderMatters:(BOOL)flag; 30 | 31 | - (id)stub; 32 | - (id)expect; 33 | - (id)reject; 34 | 35 | - (void)verify; 36 | - (void)verifyWithDelay:(NSTimeInterval)delay; 37 | 38 | - (void)stopMocking; 39 | 40 | // internal use only 41 | 42 | - (id)getNewRecorder; 43 | - (BOOL)handleInvocation:(NSInvocation *)anInvocation; 44 | - (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation; 45 | - (BOOL)handleSelector:(SEL)sel; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Headers/OCMockRecorder.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2013 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMockRecorder : NSProxy 9 | { 10 | id signatureResolver; 11 | BOOL recordedAsClassMethod; 12 | BOOL ignoreNonObjectArgs; 13 | NSInvocation *recordedInvocation; 14 | NSMutableArray *invocationHandlers; 15 | } 16 | 17 | - (id)initWithSignatureResolver:(id)anObject; 18 | 19 | - (BOOL)matchesSelector:(SEL)sel; 20 | - (BOOL)matchesInvocation:(NSInvocation *)anInvocation; 21 | - (void)releaseInvocation; 22 | 23 | - (id)andReturn:(id)anObject; 24 | - (id)andReturnValue:(NSValue *)aValue; 25 | - (id)andThrow:(NSException *)anException; 26 | - (id)andPost:(NSNotification *)aNotification; 27 | - (id)andCall:(SEL)selector onObject:(id)anObject; 28 | #if NS_BLOCKS_AVAILABLE 29 | - (id)andDo:(void (^)(NSInvocation *))block; 30 | #endif 31 | - (id)andForwardToRealObject; 32 | 33 | - (id)classMethod; 34 | - (id)ignoringNonObjectArgs; 35 | 36 | - (NSArray *)invocationHandlers; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/OCMock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nxtbgthng/UITableView-NXEmptyView/6baf75b6f0f7752c7747678d2bc81cd603648fe2/Libraries/OCMock.framework/Versions/A/OCMock -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 13C64 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | OCMock 11 | CFBundleIdentifier 12 | com.mulle-kybernetik.OCMock 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | OCMock 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTPlatformBuild 28 | 5B130a 29 | DTPlatformVersion 30 | GM 31 | DTSDKBuild 32 | 13C64 33 | DTSDKName 34 | macosx10.9 35 | DTXcode 36 | 0510 37 | DTXcodeBuild 38 | 5B130a 39 | NSHumanReadableCopyright 40 | Copyright © 2004-2013 Mulle Kybernetik. 41 | 42 | 43 | -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/A/Resources/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nxtbgthng/UITableView-NXEmptyView/6baf75b6f0f7752c7747678d2bc81cd603648fe2/Libraries/OCMock.framework/Versions/A/Resources/en.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /Libraries/OCMock.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /Libraries/SVPullToRefresh/SVPullToRefresh.h: -------------------------------------------------------------------------------- 1 | // 2 | // SVPullToRefresh.h 3 | // 4 | // Created by Sam Vermette on 23.04.12. 5 | // Copyright (c) 2012 samvermette.com. All rights reserved. 6 | // 7 | // https://github.com/samvermette/SVPullToRefresh 8 | // 9 | 10 | #import 11 | 12 | enum { 13 | SVPullToRefreshStateHidden = 1, 14 | SVPullToRefreshStateVisible, 15 | SVPullToRefreshStateTriggered, 16 | SVPullToRefreshStateLoading 17 | }; 18 | 19 | typedef NSUInteger SVPullToRefreshState; 20 | 21 | @interface SVPullToRefresh : UIView 22 | 23 | @property (nonatomic, strong) UIColor *arrowColor; 24 | @property (nonatomic, strong) UIColor *textColor; 25 | @property (nonatomic, readwrite) UIActivityIndicatorViewStyle activityIndicatorViewStyle; 26 | 27 | @property (nonatomic, strong) UILabel *dateLabel; 28 | @property (nonatomic, strong) NSDate *lastUpdatedDate; 29 | @property (nonatomic, strong) NSDateFormatter *dateFormatter; 30 | 31 | @property (nonatomic, readonly) SVPullToRefreshState state; 32 | 33 | - (void)triggerRefresh; 34 | - (void)startAnimating; 35 | - (void)stopAnimating; 36 | 37 | @end 38 | 39 | 40 | // extends UIScrollView 41 | 42 | @interface UIScrollView (SVPullToRefresh) 43 | 44 | - (void)addPullToRefreshWithActionHandler:(void (^)(void))actionHandler; 45 | - (void)addInfiniteScrollingWithActionHandler:(void (^)(void))actionHandler; 46 | 47 | @property (nonatomic, strong) SVPullToRefresh *pullToRefreshView; 48 | @property (nonatomic, strong) SVPullToRefresh *infiniteScrollingView; 49 | 50 | @property (nonatomic, assign) BOOL showsPullToRefresh; 51 | @property (nonatomic, assign) BOOL showsInfiniteScrolling; 52 | 53 | @end -------------------------------------------------------------------------------- /Libraries/SVPullToRefresh/SVPullToRefresh.m: -------------------------------------------------------------------------------- 1 | // 2 | // SVPullToRefresh.m 3 | // 4 | // Created by Sam Vermette on 23.04.12. 5 | // Copyright (c) 2012 samvermette.com. All rights reserved. 6 | // 7 | // https://github.com/samvermette/SVPullToRefresh 8 | // 9 | 10 | #import 11 | #import "SVPullToRefresh.h" 12 | 13 | static CGFloat const SVPullToRefreshViewHeight = 60; 14 | 15 | @interface SVPullToRefreshArrow : UIView 16 | @property (nonatomic, strong) UIColor *arrowColor; 17 | @end 18 | 19 | 20 | @interface SVPullToRefresh () 21 | 22 | - (id)initWithScrollView:(UIScrollView*)scrollView; 23 | - (void)rotateArrow:(float)degrees hide:(BOOL)hide; 24 | - (void)setScrollViewContentInset:(UIEdgeInsets)contentInset; 25 | - (void)scrollViewDidScroll:(CGPoint)contentOffset; 26 | 27 | - (void)startObservingScrollView; 28 | - (void)stopObservingScrollView; 29 | 30 | @property (nonatomic, copy) void (^pullToRefreshActionHandler)(void); 31 | @property (nonatomic, copy) void (^infiniteScrollingActionHandler)(void); 32 | 33 | @property (nonatomic, strong) SVPullToRefreshArrow *arrow; 34 | @property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView; 35 | @property (nonatomic, strong) UILabel *titleLabel; 36 | 37 | 38 | @property (nonatomic, unsafe_unretained) UIScrollView *scrollView; 39 | @property (nonatomic, readwrite) UIEdgeInsets originalScrollViewContentInset; 40 | @property (nonatomic, strong) UIView *originalTableFooterView; 41 | 42 | @property (nonatomic, assign) BOOL showsPullToRefresh; 43 | @property (nonatomic, assign) BOOL showsInfiniteScrolling; 44 | @property (nonatomic, assign) BOOL isObservingScrollView; 45 | 46 | @end 47 | 48 | 49 | 50 | @implementation SVPullToRefresh 51 | 52 | // public properties 53 | @synthesize pullToRefreshActionHandler, infiniteScrollingActionHandler, arrowColor, textColor, activityIndicatorViewStyle, lastUpdatedDate, dateFormatter; 54 | 55 | @synthesize state = _state; 56 | @synthesize scrollView = _scrollView; 57 | @synthesize arrow, activityIndicatorView, titleLabel, dateLabel, originalScrollViewContentInset, originalTableFooterView, showsPullToRefresh, showsInfiniteScrolling, isObservingScrollView; 58 | 59 | - (void)dealloc { 60 | [self stopObservingScrollView]; 61 | } 62 | 63 | - (id)initWithScrollView:(UIScrollView *)scrollView { 64 | self = [super initWithFrame:CGRectZero]; 65 | self.scrollView = scrollView; 66 | 67 | // default styling values 68 | self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; 69 | self.textColor = [UIColor darkGrayColor]; 70 | 71 | self.originalScrollViewContentInset = self.scrollView.contentInset; 72 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth; 73 | 74 | return self; 75 | } 76 | 77 | - (void)willMoveToSuperview:(UIView *)newSuperview { 78 | if(newSuperview == self.scrollView) 79 | [self startObservingScrollView]; 80 | else if(newSuperview == nil) 81 | [self stopObservingScrollView]; 82 | } 83 | 84 | - (void)layoutSubviews { 85 | CGFloat remainingWidth = self.superview.bounds.size.width-200; 86 | float position = 0.50; 87 | 88 | CGRect titleFrame = titleLabel.frame; 89 | titleFrame.origin.x = ceil(remainingWidth*position+44); 90 | titleLabel.frame = titleFrame; 91 | 92 | CGRect dateFrame = dateLabel.frame; 93 | dateFrame.origin.x = titleFrame.origin.x; 94 | dateLabel.frame = dateFrame; 95 | 96 | CGRect arrowFrame = arrow.frame; 97 | arrowFrame.origin.x = ceil(remainingWidth*position); 98 | arrow.frame = arrowFrame; 99 | 100 | if(infiniteScrollingActionHandler) { 101 | self.activityIndicatorView.center = CGPointMake(round(self.bounds.size.width/2), round(self.bounds.size.height/2)); 102 | } else 103 | self.activityIndicatorView.center = self.arrow.center; 104 | 105 | } 106 | 107 | #pragma mark - Getters 108 | 109 | - (SVPullToRefreshArrow *)arrow { 110 | if(!arrow && pullToRefreshActionHandler) { 111 | self.arrow = [[SVPullToRefreshArrow alloc]initWithFrame:CGRectMake(0, 6, 22, 48)]; 112 | arrow.backgroundColor = [UIColor clearColor]; 113 | 114 | // assign a different default color for arrow 115 | // arrow.arrowColor = [UIColor blueColor]; 116 | } 117 | return arrow; 118 | } 119 | 120 | - (UIActivityIndicatorView *)activityIndicatorView { 121 | if(!activityIndicatorView) { 122 | activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 123 | activityIndicatorView.hidesWhenStopped = YES; 124 | [self addSubview:activityIndicatorView]; 125 | } 126 | return activityIndicatorView; 127 | } 128 | 129 | - (UILabel *)dateLabel { 130 | if(!dateLabel && pullToRefreshActionHandler) { 131 | dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 28, 180, 20)]; 132 | dateLabel.font = [UIFont systemFontOfSize:12]; 133 | dateLabel.backgroundColor = [UIColor clearColor]; 134 | dateLabel.textColor = textColor; 135 | [self addSubview:dateLabel]; 136 | 137 | CGRect titleFrame = titleLabel.frame; 138 | titleFrame.origin.y = 12; 139 | titleLabel.frame = titleFrame; 140 | } 141 | return dateLabel; 142 | } 143 | 144 | - (NSDateFormatter *)dateFormatter { 145 | if(!dateFormatter) { 146 | dateFormatter = [[NSDateFormatter alloc] init]; 147 | [dateFormatter setDateStyle:NSDateFormatterShortStyle]; 148 | [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; 149 | dateFormatter.locale = [NSLocale currentLocale]; 150 | } 151 | return dateFormatter; 152 | } 153 | 154 | - (UIEdgeInsets)originalScrollViewContentInset { 155 | return UIEdgeInsetsMake(originalScrollViewContentInset.top, self.scrollView.contentInset.left, self.scrollView.contentInset.bottom, self.scrollView.contentInset.right); 156 | } 157 | 158 | #pragma mark - Setters 159 | 160 | - (void)setPullToRefreshActionHandler:(void (^)(void))actionHandler { 161 | pullToRefreshActionHandler = [actionHandler copy]; 162 | [_scrollView addSubview:self]; 163 | self.showsPullToRefresh = YES; 164 | 165 | // If the titleLabel is added before, there is no need to add again. 166 | if (self.titleLabel == nil) { 167 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 150, 20)]; 168 | titleLabel.text = NSLocalizedString(@"Pull to refresh...",); 169 | titleLabel.font = [UIFont boldSystemFontOfSize:14]; 170 | titleLabel.backgroundColor = [UIColor clearColor]; 171 | titleLabel.textColor = textColor; 172 | [self addSubview:titleLabel]; 173 | } 174 | 175 | [self addSubview:self.arrow]; 176 | 177 | self.state = SVPullToRefreshStateHidden; 178 | self.frame = CGRectMake(0, -SVPullToRefreshViewHeight, self.scrollView.bounds.size.width, SVPullToRefreshViewHeight); 179 | } 180 | 181 | - (void)setInfiniteScrollingActionHandler:(void (^)(void))actionHandler { 182 | self.originalTableFooterView = [(UITableView*)self.scrollView tableFooterView]; 183 | infiniteScrollingActionHandler = [actionHandler copy]; 184 | self.showsInfiniteScrolling = YES; 185 | self.frame = CGRectMake(0, 0, self.scrollView.bounds.size.width, SVPullToRefreshViewHeight); 186 | [(UITableView*)self.scrollView setTableFooterView:self]; 187 | self.state = SVPullToRefreshStateHidden; 188 | [self layoutSubviews]; 189 | } 190 | 191 | - (void)setArrowColor:(UIColor *)newArrowColor { 192 | self.arrow.arrowColor = newArrowColor; // pass through 193 | [self.arrow setNeedsDisplay]; 194 | } 195 | 196 | - (UIColor *)arrowColor { 197 | return self.arrow.arrowColor; // pass through 198 | } 199 | 200 | - (void)setTextColor:(UIColor *)newTextColor { 201 | textColor = newTextColor; 202 | titleLabel.textColor = newTextColor; 203 | dateLabel.textColor = newTextColor; 204 | } 205 | 206 | - (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)viewStyle { 207 | self.activityIndicatorView.activityIndicatorViewStyle = viewStyle; 208 | } 209 | 210 | - (void)setScrollViewContentInset:(UIEdgeInsets)contentInset { 211 | [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationOptionBeginFromCurrentState animations:^{ 212 | self.scrollView.contentInset = contentInset; 213 | } completion:^(BOOL finished) { 214 | if(self.state == SVPullToRefreshStateHidden && contentInset.top == self.originalScrollViewContentInset.top) 215 | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 216 | arrow.alpha = 0; 217 | } completion:NULL]; 218 | }]; 219 | } 220 | 221 | - (void)setLastUpdatedDate:(NSDate *)newLastUpdatedDate { 222 | self.dateLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Last Updated: %@",), newLastUpdatedDate?[self.dateFormatter stringFromDate:newLastUpdatedDate]:NSLocalizedString(@"Never",)]; 223 | } 224 | 225 | - (void)setDateFormatter:(NSDateFormatter *)newDateFormatter { 226 | dateFormatter = newDateFormatter; 227 | self.dateLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Last Updated: %@",), self.lastUpdatedDate?[newDateFormatter stringFromDate:self.lastUpdatedDate]:NSLocalizedString(@"Never",)]; 228 | } 229 | 230 | - (void)setShowsInfiniteScrolling:(BOOL)show { 231 | showsInfiniteScrolling = show; 232 | if(!show) 233 | [(UITableView*)self.scrollView setTableFooterView:self.originalTableFooterView]; 234 | else 235 | [(UITableView*)self.scrollView setTableFooterView:self]; 236 | } 237 | 238 | #pragma mark - 239 | 240 | - (void)startObservingScrollView { 241 | if (self.isObservingScrollView) 242 | return; 243 | 244 | [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil]; 245 | [self.scrollView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil]; 246 | self.isObservingScrollView = YES; 247 | } 248 | 249 | - (void)stopObservingScrollView { 250 | if(!self.isObservingScrollView) 251 | return; 252 | 253 | [self.scrollView removeObserver:self forKeyPath:@"contentOffset"]; 254 | [self.scrollView removeObserver:self forKeyPath:@"frame"]; 255 | self.isObservingScrollView = NO; 256 | } 257 | 258 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 259 | if([keyPath isEqualToString:@"contentOffset"]) 260 | [self scrollViewDidScroll:[[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]]; 261 | else if([keyPath isEqualToString:@"frame"]) 262 | [self layoutSubviews]; 263 | } 264 | 265 | - (void)scrollViewDidScroll:(CGPoint)contentOffset { 266 | if(pullToRefreshActionHandler) { 267 | if (self.state == SVPullToRefreshStateLoading) { 268 | CGFloat offset = MAX(self.scrollView.contentOffset.y * -1, 0); 269 | offset = MIN(offset, self.originalScrollViewContentInset.top + SVPullToRefreshViewHeight); 270 | self.scrollView.contentInset = UIEdgeInsetsMake(offset, 0.0f, 0.0f, 0.0f); 271 | } else { 272 | CGFloat scrollOffsetThreshold = self.frame.origin.y-self.originalScrollViewContentInset.top; 273 | 274 | if(!self.scrollView.isDragging && self.state == SVPullToRefreshStateTriggered) 275 | self.state = SVPullToRefreshStateLoading; 276 | else if(contentOffset.y > scrollOffsetThreshold && contentOffset.y < -self.originalScrollViewContentInset.top && self.scrollView.isDragging && self.state != SVPullToRefreshStateLoading) 277 | self.state = SVPullToRefreshStateVisible; 278 | else if(contentOffset.y < scrollOffsetThreshold && self.scrollView.isDragging && self.state == SVPullToRefreshStateVisible) 279 | self.state = SVPullToRefreshStateTriggered; 280 | else if(contentOffset.y >= -self.originalScrollViewContentInset.top && self.state != SVPullToRefreshStateHidden) 281 | self.state = SVPullToRefreshStateHidden; 282 | } 283 | } 284 | else if(infiniteScrollingActionHandler) { 285 | CGFloat scrollOffsetThreshold = self.scrollView.contentSize.height-self.scrollView.bounds.size.height-self.originalScrollViewContentInset.top; 286 | 287 | if(contentOffset.y > MAX(scrollOffsetThreshold, self.scrollView.bounds.size.height-self.scrollView.contentSize.height) && self.state == SVPullToRefreshStateHidden) 288 | self.state = SVPullToRefreshStateLoading; 289 | else if(contentOffset.y < scrollOffsetThreshold) 290 | self.state = SVPullToRefreshStateHidden; 291 | } 292 | } 293 | 294 | - (void)triggerRefresh { 295 | self.state = SVPullToRefreshStateLoading; 296 | [self.scrollView setContentOffset:CGPointMake(0, -SVPullToRefreshViewHeight) animated:YES]; 297 | } 298 | 299 | - (void)startAnimating{ 300 | _state = SVPullToRefreshStateLoading; 301 | 302 | titleLabel.text = NSLocalizedString(@"Loading...",); 303 | [self.activityIndicatorView startAnimating]; 304 | UIEdgeInsets newInsets = self.originalScrollViewContentInset; 305 | newInsets.top = self.frame.origin.y*-1+self.originalScrollViewContentInset.top; 306 | newInsets.bottom = self.scrollView.contentInset.bottom; 307 | [self setScrollViewContentInset:newInsets]; 308 | [self.scrollView setContentOffset:CGPointMake(0, -self.frame.size.height) animated:NO]; 309 | [self rotateArrow:0 hide:YES]; 310 | } 311 | 312 | - (void)stopAnimating { 313 | self.state = SVPullToRefreshStateHidden; 314 | } 315 | 316 | - (void)setState:(SVPullToRefreshState)newState { 317 | 318 | if(pullToRefreshActionHandler && !self.showsPullToRefresh && !self.activityIndicatorView.isAnimating) { 319 | titleLabel.text = NSLocalizedString(@"",); 320 | [self.activityIndicatorView stopAnimating]; 321 | [self setScrollViewContentInset:self.originalScrollViewContentInset]; 322 | [self rotateArrow:0 hide:YES]; 323 | return; 324 | } 325 | 326 | if(infiniteScrollingActionHandler && !self.showsInfiniteScrolling) 327 | return; 328 | 329 | if(_state == newState) 330 | return; 331 | 332 | _state = newState; 333 | 334 | if(pullToRefreshActionHandler) { 335 | switch (newState) { 336 | case SVPullToRefreshStateHidden: 337 | titleLabel.text = NSLocalizedString(@"Pull to refresh...",); 338 | [self.activityIndicatorView stopAnimating]; 339 | [self setScrollViewContentInset:self.originalScrollViewContentInset]; 340 | [self rotateArrow:0 hide:NO]; 341 | break; 342 | 343 | case SVPullToRefreshStateVisible: 344 | titleLabel.text = NSLocalizedString(@"Pull to refresh...",); 345 | arrow.alpha = 1; 346 | [self.activityIndicatorView stopAnimating]; 347 | [self setScrollViewContentInset:self.originalScrollViewContentInset]; 348 | [self rotateArrow:0 hide:NO]; 349 | break; 350 | 351 | case SVPullToRefreshStateTriggered: 352 | titleLabel.text = NSLocalizedString(@"Release to refresh...",); 353 | [self rotateArrow:M_PI hide:NO]; 354 | break; 355 | 356 | case SVPullToRefreshStateLoading: 357 | [self startAnimating]; 358 | pullToRefreshActionHandler(); 359 | break; 360 | } 361 | } 362 | else if(infiniteScrollingActionHandler) { 363 | switch (newState) { 364 | case SVPullToRefreshStateHidden: 365 | [self.activityIndicatorView stopAnimating]; 366 | break; 367 | 368 | case SVPullToRefreshStateLoading: 369 | [self.activityIndicatorView startAnimating]; 370 | infiniteScrollingActionHandler(); 371 | break; 372 | } 373 | } 374 | } 375 | 376 | - (void)rotateArrow:(float)degrees hide:(BOOL)hide { 377 | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 378 | self.arrow.layer.transform = CATransform3DMakeRotation(degrees, 0, 0, 1); 379 | self.arrow.layer.opacity = !hide; 380 | //[self.arrow setNeedsDisplay];//ios 4 381 | } completion:NULL]; 382 | } 383 | 384 | @end 385 | 386 | 387 | #pragma mark - UIScrollView (SVPullToRefresh) 388 | #import 389 | 390 | static char UIScrollViewPullToRefreshView; 391 | static char UIScrollViewInfiniteScrollingView; 392 | 393 | @implementation UIScrollView (SVPullToRefresh) 394 | 395 | @dynamic pullToRefreshView, showsPullToRefresh, infiniteScrollingView, showsInfiniteScrolling; 396 | 397 | - (void)willMoveToSuperview:(UIView *)newSuperview { 398 | if(!newSuperview) { 399 | [self.pullToRefreshView removeFromSuperview]; 400 | self.pullToRefreshView = nil; 401 | 402 | [self.infiniteScrollingView removeFromSuperview]; 403 | self.infiniteScrollingView = nil; 404 | } 405 | } 406 | 407 | - (void)addPullToRefreshWithActionHandler:(void (^)(void))actionHandler { 408 | self.pullToRefreshView.pullToRefreshActionHandler = actionHandler; 409 | } 410 | 411 | - (void)addInfiniteScrollingWithActionHandler:(void (^)(void))actionHandler { 412 | self.infiniteScrollingView.infiniteScrollingActionHandler = actionHandler; 413 | } 414 | 415 | - (void)setPullToRefreshView:(SVPullToRefresh *)pullToRefreshView { 416 | [self willChangeValueForKey:@"pullToRefreshView"]; 417 | objc_setAssociatedObject(self, &UIScrollViewPullToRefreshView, 418 | pullToRefreshView, 419 | OBJC_ASSOCIATION_RETAIN); 420 | [self didChangeValueForKey:@"pullToRefreshView"]; 421 | } 422 | 423 | - (void)setInfiniteScrollingView:(SVPullToRefresh *)pullToRefreshView { 424 | [self willChangeValueForKey:@"infiniteScrollingView"]; 425 | objc_setAssociatedObject(self, &UIScrollViewInfiniteScrollingView, 426 | pullToRefreshView, 427 | OBJC_ASSOCIATION_RETAIN); 428 | [self didChangeValueForKey:@"infiniteScrollingView"]; 429 | } 430 | 431 | - (SVPullToRefresh *)pullToRefreshView { 432 | SVPullToRefresh *pullToRefreshView = objc_getAssociatedObject(self, &UIScrollViewPullToRefreshView); 433 | if(!pullToRefreshView) { 434 | pullToRefreshView = [[SVPullToRefresh alloc] initWithScrollView:self]; 435 | self.pullToRefreshView = pullToRefreshView; 436 | } 437 | return pullToRefreshView; 438 | } 439 | 440 | - (void)setShowsPullToRefresh:(BOOL)showsPullToRefresh { 441 | self.pullToRefreshView.showsPullToRefresh = showsPullToRefresh; 442 | } 443 | 444 | - (BOOL)showsPullToRefresh { 445 | return self.pullToRefreshView.showsPullToRefresh; 446 | } 447 | 448 | - (SVPullToRefresh *)infiniteScrollingView { 449 | SVPullToRefresh *infiniteScrollingView = objc_getAssociatedObject(self, &UIScrollViewInfiniteScrollingView); 450 | if(!infiniteScrollingView) { 451 | infiniteScrollingView = [[SVPullToRefresh alloc] initWithScrollView:self]; 452 | self.infiniteScrollingView = infiniteScrollingView; 453 | } 454 | return infiniteScrollingView; 455 | } 456 | 457 | - (void)setShowsInfiniteScrolling:(BOOL)showsInfiniteScrolling { 458 | self.infiniteScrollingView.showsInfiniteScrolling = showsInfiniteScrolling; 459 | } 460 | 461 | - (BOOL)showsInfiniteScrolling { 462 | return self.infiniteScrollingView.showsInfiniteScrolling; 463 | } 464 | 465 | @end 466 | 467 | 468 | #pragma mark - SVPullToRefreshArrow 469 | 470 | @implementation SVPullToRefreshArrow 471 | @synthesize arrowColor; 472 | 473 | - (UIColor *)arrowColor { 474 | if (arrowColor) return arrowColor; 475 | return [UIColor grayColor]; // default Color 476 | } 477 | 478 | - (void)drawRect:(CGRect)rect { 479 | CGContextRef c = UIGraphicsGetCurrentContext(); 480 | 481 | // the rects above the arrow 482 | CGContextAddRect(c, CGRectMake(5, 0, 12, 4)); // to-do: use dynamic points 483 | CGContextAddRect(c, CGRectMake(5, 6, 12, 4)); // currently fixed size: 22 x 48pt 484 | CGContextAddRect(c, CGRectMake(5, 12, 12, 4)); 485 | CGContextAddRect(c, CGRectMake(5, 18, 12, 4)); 486 | CGContextAddRect(c, CGRectMake(5, 24, 12, 4)); 487 | CGContextAddRect(c, CGRectMake(5, 30, 12, 4)); 488 | 489 | // the arrow 490 | CGContextMoveToPoint(c, 0, 34); 491 | CGContextAddLineToPoint(c, 11, 48); 492 | CGContextAddLineToPoint(c, 22, 34); 493 | CGContextAddLineToPoint(c, 0, 34); 494 | CGContextClosePath(c); 495 | 496 | CGContextSaveGState(c); 497 | CGContextClip(c); 498 | 499 | // Gradient Declaration 500 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 501 | CGFloat alphaGradientLocations[] = {0, 0.8}; 502 | 503 | CGGradientRef alphaGradient = nil; 504 | if([[[UIDevice currentDevice] systemVersion]floatValue] >= 5){ 505 | NSArray* alphaGradientColors = [NSArray arrayWithObjects: 506 | (id)[self.arrowColor colorWithAlphaComponent:0].CGColor, 507 | (id)[self.arrowColor colorWithAlphaComponent:1].CGColor, 508 | nil]; 509 | alphaGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)alphaGradientColors, alphaGradientLocations); 510 | }else{ 511 | const CGFloat * components = CGColorGetComponents([self.arrowColor CGColor]); 512 | int numComponents = CGColorGetNumberOfComponents([self.arrowColor CGColor]); 513 | CGFloat colors[8]; 514 | switch(numComponents){ 515 | case 2:{ 516 | colors[0] = colors[4] = components[0]; 517 | colors[1] = colors[5] = components[0]; 518 | colors[2] = colors[6] = components[0]; 519 | break; 520 | } 521 | case 4:{ 522 | colors[0] = colors[4] = components[0]; 523 | colors[1] = colors[5] = components[1]; 524 | colors[2] = colors[6] = components[2]; 525 | break; 526 | } 527 | } 528 | colors[3] = 0; 529 | colors[7] = 1; 530 | alphaGradient = CGGradientCreateWithColorComponents(colorSpace,colors,alphaGradientLocations,2); 531 | } 532 | 533 | 534 | CGContextDrawLinearGradient(c, alphaGradient, CGPointZero, CGPointMake(0, rect.size.height), 0); 535 | 536 | CGContextRestoreGState(c); 537 | 538 | CGGradientRelease(alphaGradient); 539 | CGColorSpaceRelease(colorSpace); 540 | } 541 | @end 542 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # NXEmptyView for UITableView 2 | 3 | ## What is this? 4 | 5 | ... a category that dynamically shows an _empty view_ when there are no entries in your table view. 6 | 7 | ## Behavior 8 | 9 | The empty view will be displayed whenever the table view has no cells in any section. Of course only if a view has been set via `nxEV_emptyView`. 10 | Whenever the table view is reloaded or layouted the empty view gets updated. 11 | 12 | The frame of the empty view is updated to the bounds of the table view, so make sure it layouts nicely for all the orientations and screen sizes (iPhone 5, yay) that you're targeting. 13 | 14 | ### Bypassing the Empty View 15 | 16 | There might be scenarios in which you don't want the empty view to appear. For example when the content of the list has not yet been loaded and you don't want to scream at the user that there's none just because it has not yet been loaded. 17 | 18 | In that case you can let your table view datasource implement the `UITableViewNXEmptyViewDataSource` protocol and return `NO` in `-tableViewShouldBypassNXEmptyView:`. Whenever this value changes do a `-[UITableView reloadData]` to update the empty view. 19 | 20 | ## Install 21 | 22 | ### Via Cocoapods 23 | 24 | Add this to your Podfile 25 | 26 | pod 'UITableView-NXEmptyView' 27 | 28 | In your table view do: 29 | 30 | - `#import ` 31 | - Set the `nxEV_emptyView` property of the table view with the view you want to be displayed when the table is empty. 32 | You can use the Interface Builder to do so as well. 33 | 34 | ## Contribute 35 | 36 | Contributions are highly welcomed! 37 | 38 | - Fork the repo 39 | - Add your contribution 40 | - Add a test for it if necessary 41 | - Send us a [pull request](https://github.com/nxtbgthng/UITableView-NXEmptyView/pull/new/master) describing your changes 42 | - Receive virtual high fives! :hand: 43 | 44 | Bonus points for feature branches :sunglasses: 45 | 46 | ### Contributors 47 | 48 | - Your name here? 49 | 50 | 51 | ## License 52 | 53 | This code is released under the _3-clause BSD License_ (aka _new BSD License_ or _modified BSD License_). 54 | The full text is included in the LICENSE file in the root of the repository. 55 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9405A431162479BA00E83BB5 /* SVPullToRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 9405A430162479BA00E83BB5 /* SVPullToRefresh.m */; }; 11 | 9405A43516247A0600E83BB5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9405A43416247A0600E83BB5 /* QuartzCore.framework */; }; 12 | 9438A10D1593E4110042CA60 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9438A10B1593E4110042CA60 /* InfoPlist.strings */; }; 13 | 9438A1171593E4120042CA60 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1161593E4120042CA60 /* SenTestingKit.framework */; }; 14 | 9438A1191593E4120042CA60 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1181593E4120042CA60 /* UIKit.framework */; }; 15 | 9438A11B1593E4120042CA60 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A11A1593E4120042CA60 /* Foundation.framework */; }; 16 | 9438A11E1593E4120042CA60 /* UITableView+NXEmptyView.framework in Resources */ = {isa = PBXBuildFile; fileRef = 9438A1061593E4110042CA60 /* UITableView+NXEmptyView.framework */; }; 17 | 9438A1241593E4120042CA60 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9438A1221593E4120042CA60 /* InfoPlist.strings */; }; 18 | 9438A1271593E4120042CA60 /* UITableView_NXEmptyViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9438A1261593E4120042CA60 /* UITableView_NXEmptyViewTests.m */; }; 19 | 9438A1361593E4410042CA60 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1181593E4120042CA60 /* UIKit.framework */; }; 20 | 9438A1371593E4410042CA60 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A11A1593E4120042CA60 /* Foundation.framework */; }; 21 | 9438A1391593E4410042CA60 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1381593E4410042CA60 /* CoreGraphics.framework */; }; 22 | 9438A13F1593E4410042CA60 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9438A13D1593E4410042CA60 /* InfoPlist.strings */; }; 23 | 9438A1411593E4410042CA60 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9438A1401593E4410042CA60 /* main.m */; }; 24 | 9438A1451593E4410042CA60 /* NXAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9438A1441593E4410042CA60 /* NXAppDelegate.m */; }; 25 | 9438A1481593E4410042CA60 /* NXViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9438A1471593E4410042CA60 /* NXViewController.m */; }; 26 | 9438A14B1593E4410042CA60 /* NXViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9438A1491593E4410042CA60 /* NXViewController.xib */; }; 27 | 9438A1511593E45E0042CA60 /* UITableView+NXEmptyView.h in Headers */ = {isa = PBXBuildFile; fileRef = 9438A14F1593E45E0042CA60 /* UITableView+NXEmptyView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | 9438A1521593E45E0042CA60 /* UITableView+NXEmptyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9438A1501593E45E0042CA60 /* UITableView+NXEmptyView.m */; }; 29 | 9438A1531593E4780042CA60 /* UITableView+NXEmptyView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1061593E4110042CA60 /* UITableView+NXEmptyView.framework */; }; 30 | 9438A18415940E490042CA60 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A17C15940E380042CA60 /* libOCMock.a */; }; 31 | 9438A1861594196E0042CA60 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9438A1381593E4410042CA60 /* CoreGraphics.framework */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | 9438A11C1593E4120042CA60 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 9438A0F91593E4110042CA60 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 9438A1051593E4110042CA60; 40 | remoteInfo = "UITableView+NXEmptyView"; 41 | }; 42 | 9438A1541593E6FD0042CA60 /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 9438A0F91593E4110042CA60 /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 9438A1051593E4110042CA60; 47 | remoteInfo = "UITableView+NXEmptyView"; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 9405A42F162479BA00E83BB5 /* SVPullToRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SVPullToRefresh.h; path = Libraries/SVPullToRefresh/SVPullToRefresh.h; sourceTree = SOURCE_ROOT; }; 53 | 9405A430162479BA00E83BB5 /* SVPullToRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SVPullToRefresh.m; path = Libraries/SVPullToRefresh/SVPullToRefresh.m; sourceTree = SOURCE_ROOT; }; 54 | 9405A43416247A0600E83BB5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 55 | 9438A1061593E4110042CA60 /* UITableView+NXEmptyView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UITableView+NXEmptyView.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 9438A10A1593E4110042CA60 /* UITableView+NXEmptyView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UITableView+NXEmptyView-Info.plist"; sourceTree = ""; }; 57 | 9438A10C1593E4110042CA60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | 9438A10E1593E4110042CA60 /* UITableView+NXEmptyView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UITableView+NXEmptyView-Prefix.pch"; sourceTree = ""; }; 59 | 9438A1141593E4120042CA60 /* UITableView+NXEmptyViewTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UITableView+NXEmptyViewTests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 9438A1161593E4120042CA60 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 61 | 9438A1181593E4120042CA60 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 62 | 9438A11A1593E4120042CA60 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 63 | 9438A1211593E4120042CA60 /* UITableView+NXEmptyViewTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UITableView+NXEmptyViewTests-Info.plist"; sourceTree = ""; }; 64 | 9438A1231593E4120042CA60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 65 | 9438A1251593E4120042CA60 /* UITableView_NXEmptyViewTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UITableView_NXEmptyViewTests.h; sourceTree = ""; }; 66 | 9438A1261593E4120042CA60 /* UITableView_NXEmptyViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UITableView_NXEmptyViewTests.m; sourceTree = ""; }; 67 | 9438A1341593E4410042CA60 /* DemoApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 9438A1381593E4410042CA60 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 69 | 9438A13C1593E4410042CA60 /* DemoApp-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DemoApp-Info.plist"; sourceTree = ""; }; 70 | 9438A13E1593E4410042CA60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 71 | 9438A1401593E4410042CA60 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 72 | 9438A1421593E4410042CA60 /* DemoApp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DemoApp-Prefix.pch"; sourceTree = ""; }; 73 | 9438A1431593E4410042CA60 /* NXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NXAppDelegate.h; sourceTree = ""; }; 74 | 9438A1441593E4410042CA60 /* NXAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NXAppDelegate.m; sourceTree = ""; }; 75 | 9438A1461593E4410042CA60 /* NXViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NXViewController.h; sourceTree = ""; }; 76 | 9438A1471593E4410042CA60 /* NXViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NXViewController.m; sourceTree = ""; }; 77 | 9438A14A1593E4410042CA60 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/NXViewController.xib; sourceTree = ""; }; 78 | 9438A14F1593E45E0042CA60 /* UITableView+NXEmptyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+NXEmptyView.h"; sourceTree = ""; }; 79 | 9438A1501593E45E0042CA60 /* UITableView+NXEmptyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+NXEmptyView.m"; sourceTree = ""; }; 80 | 9438A17C15940E380042CA60 /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = ""; }; 81 | 9438A17E15940E380042CA60 /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = ""; }; 82 | 9438A17F15940E380042CA60 /* OCMArg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = ""; }; 83 | 9438A18015940E380042CA60 /* OCMConstraint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMConstraint.h; sourceTree = ""; }; 84 | 9438A18115940E380042CA60 /* OCMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMock.h; sourceTree = ""; }; 85 | 9438A18215940E380042CA60 /* OCMockObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = ""; }; 86 | 9438A18315940E380042CA60 /* OCMockRecorder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMockRecorder.h; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 9438A1001593E4110042CA60 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 9438A1101593E4120042CA60 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 9438A1861594196E0042CA60 /* CoreGraphics.framework in Frameworks */, 102 | 9438A1171593E4120042CA60 /* SenTestingKit.framework in Frameworks */, 103 | 9438A18415940E490042CA60 /* libOCMock.a in Frameworks */, 104 | 9438A1191593E4120042CA60 /* UIKit.framework in Frameworks */, 105 | 9438A11B1593E4120042CA60 /* Foundation.framework in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | 9438A1311593E4410042CA60 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | 9438A1531593E4780042CA60 /* UITableView+NXEmptyView.framework in Frameworks */, 114 | 9438A1361593E4410042CA60 /* UIKit.framework in Frameworks */, 115 | 9438A1371593E4410042CA60 /* Foundation.framework in Frameworks */, 116 | 9438A1391593E4410042CA60 /* CoreGraphics.framework in Frameworks */, 117 | 9405A43516247A0600E83BB5 /* QuartzCore.framework in Frameworks */, 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | /* End PBXFrameworksBuildPhase section */ 122 | 123 | /* Begin PBXGroup section */ 124 | 9405A433162479BF00E83BB5 /* SVPullToRefresh */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 9405A42F162479BA00E83BB5 /* SVPullToRefresh.h */, 128 | 9405A430162479BA00E83BB5 /* SVPullToRefresh.m */, 129 | ); 130 | name = SVPullToRefresh; 131 | sourceTree = ""; 132 | }; 133 | 9405A43616247A1700E83BB5 /* Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 9405A43416247A0600E83BB5 /* QuartzCore.framework */, 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | 9438A0F71593E4110042CA60 = { 142 | isa = PBXGroup; 143 | children = ( 144 | 9438A17915940E010042CA60 /* Libraries */, 145 | 9438A1081593E4110042CA60 /* UITableView+NXEmptyView */, 146 | 9438A11F1593E4120042CA60 /* UITableView+NXEmptyViewTests */, 147 | 9438A13A1593E4410042CA60 /* DemoApp */, 148 | 9438A1151593E4120042CA60 /* Frameworks */, 149 | 9438A1071593E4110042CA60 /* Products */, 150 | ); 151 | sourceTree = ""; 152 | }; 153 | 9438A1071593E4110042CA60 /* Products */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 9438A1061593E4110042CA60 /* UITableView+NXEmptyView.framework */, 157 | 9438A1141593E4120042CA60 /* UITableView+NXEmptyViewTests.octest */, 158 | 9438A1341593E4410042CA60 /* DemoApp.app */, 159 | ); 160 | name = Products; 161 | sourceTree = ""; 162 | }; 163 | 9438A1081593E4110042CA60 /* UITableView+NXEmptyView */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 9438A14F1593E45E0042CA60 /* UITableView+NXEmptyView.h */, 167 | 9438A1501593E45E0042CA60 /* UITableView+NXEmptyView.m */, 168 | 9438A1091593E4110042CA60 /* Supporting Files */, 169 | ); 170 | path = "UITableView+NXEmptyView"; 171 | sourceTree = ""; 172 | }; 173 | 9438A1091593E4110042CA60 /* Supporting Files */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 9438A10A1593E4110042CA60 /* UITableView+NXEmptyView-Info.plist */, 177 | 9438A10B1593E4110042CA60 /* InfoPlist.strings */, 178 | 9438A10E1593E4110042CA60 /* UITableView+NXEmptyView-Prefix.pch */, 179 | ); 180 | name = "Supporting Files"; 181 | sourceTree = ""; 182 | }; 183 | 9438A1151593E4120042CA60 /* Frameworks */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 9438A1161593E4120042CA60 /* SenTestingKit.framework */, 187 | 9438A1181593E4120042CA60 /* UIKit.framework */, 188 | 9438A11A1593E4120042CA60 /* Foundation.framework */, 189 | 9438A1381593E4410042CA60 /* CoreGraphics.framework */, 190 | ); 191 | name = Frameworks; 192 | sourceTree = ""; 193 | }; 194 | 9438A11F1593E4120042CA60 /* UITableView+NXEmptyViewTests */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 9438A1251593E4120042CA60 /* UITableView_NXEmptyViewTests.h */, 198 | 9438A1261593E4120042CA60 /* UITableView_NXEmptyViewTests.m */, 199 | 9438A1201593E4120042CA60 /* Supporting Files */, 200 | ); 201 | path = "UITableView+NXEmptyViewTests"; 202 | sourceTree = ""; 203 | }; 204 | 9438A1201593E4120042CA60 /* Supporting Files */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 9438A1211593E4120042CA60 /* UITableView+NXEmptyViewTests-Info.plist */, 208 | 9438A1221593E4120042CA60 /* InfoPlist.strings */, 209 | ); 210 | name = "Supporting Files"; 211 | sourceTree = ""; 212 | }; 213 | 9438A13A1593E4410042CA60 /* DemoApp */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 9438A1431593E4410042CA60 /* NXAppDelegate.h */, 217 | 9438A1441593E4410042CA60 /* NXAppDelegate.m */, 218 | 9438A1461593E4410042CA60 /* NXViewController.h */, 219 | 9438A1471593E4410042CA60 /* NXViewController.m */, 220 | 9438A1491593E4410042CA60 /* NXViewController.xib */, 221 | 9405A433162479BF00E83BB5 /* SVPullToRefresh */, 222 | 9438A13B1593E4410042CA60 /* Supporting Files */, 223 | 9405A43616247A1700E83BB5 /* Frameworks */, 224 | ); 225 | path = DemoApp; 226 | sourceTree = ""; 227 | }; 228 | 9438A13B1593E4410042CA60 /* Supporting Files */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | 9438A13C1593E4410042CA60 /* DemoApp-Info.plist */, 232 | 9438A13D1593E4410042CA60 /* InfoPlist.strings */, 233 | 9438A1401593E4410042CA60 /* main.m */, 234 | 9438A1421593E4410042CA60 /* DemoApp-Prefix.pch */, 235 | ); 236 | name = "Supporting Files"; 237 | sourceTree = ""; 238 | }; 239 | 9438A17915940E010042CA60 /* Libraries */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | 9438A17C15940E380042CA60 /* libOCMock.a */, 243 | 9438A17D15940E380042CA60 /* OCMock */, 244 | ); 245 | path = Libraries; 246 | sourceTree = ""; 247 | }; 248 | 9438A17D15940E380042CA60 /* OCMock */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | 9438A17E15940E380042CA60 /* NSNotificationCenter+OCMAdditions.h */, 252 | 9438A17F15940E380042CA60 /* OCMArg.h */, 253 | 9438A18015940E380042CA60 /* OCMConstraint.h */, 254 | 9438A18115940E380042CA60 /* OCMock.h */, 255 | 9438A18215940E380042CA60 /* OCMockObject.h */, 256 | 9438A18315940E380042CA60 /* OCMockRecorder.h */, 257 | ); 258 | path = OCMock; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXGroup section */ 262 | 263 | /* Begin PBXHeadersBuildPhase section */ 264 | 9438A1011593E4110042CA60 /* Headers */ = { 265 | isa = PBXHeadersBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | 9438A1511593E45E0042CA60 /* UITableView+NXEmptyView.h in Headers */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | /* End PBXHeadersBuildPhase section */ 273 | 274 | /* Begin PBXNativeTarget section */ 275 | 9438A1051593E4110042CA60 /* UITableView+NXEmptyView */ = { 276 | isa = PBXNativeTarget; 277 | buildConfigurationList = 9438A12A1593E4120042CA60 /* Build configuration list for PBXNativeTarget "UITableView+NXEmptyView" */; 278 | buildPhases = ( 279 | 9438A0FE1593E4110042CA60 /* ShellScript */, 280 | 9438A0FF1593E4110042CA60 /* Sources */, 281 | 9438A1001593E4110042CA60 /* Frameworks */, 282 | 9438A1011593E4110042CA60 /* Headers */, 283 | 9438A1021593E4110042CA60 /* Resources */, 284 | 9438A1031593E4110042CA60 /* ShellScript */, 285 | 9438A1041593E4110042CA60 /* ShellScript */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | ); 291 | name = "UITableView+NXEmptyView"; 292 | productName = "UITableView+NXEmptyView"; 293 | productReference = 9438A1061593E4110042CA60 /* UITableView+NXEmptyView.framework */; 294 | productType = "com.apple.product-type.bundle"; 295 | }; 296 | 9438A1131593E4120042CA60 /* UITableView+NXEmptyViewTests */ = { 297 | isa = PBXNativeTarget; 298 | buildConfigurationList = 9438A12D1593E4120042CA60 /* Build configuration list for PBXNativeTarget "UITableView+NXEmptyViewTests" */; 299 | buildPhases = ( 300 | 9438A10F1593E4120042CA60 /* Sources */, 301 | 9438A1101593E4120042CA60 /* Frameworks */, 302 | 9438A1111593E4120042CA60 /* Resources */, 303 | 9438A1121593E4120042CA60 /* ShellScript */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | 9438A11D1593E4120042CA60 /* PBXTargetDependency */, 309 | ); 310 | name = "UITableView+NXEmptyViewTests"; 311 | productName = "UITableView+NXEmptyViewTests"; 312 | productReference = 9438A1141593E4120042CA60 /* UITableView+NXEmptyViewTests.octest */; 313 | productType = "com.apple.product-type.bundle"; 314 | }; 315 | 9438A1331593E4410042CA60 /* DemoApp */ = { 316 | isa = PBXNativeTarget; 317 | buildConfigurationList = 9438A14C1593E4410042CA60 /* Build configuration list for PBXNativeTarget "DemoApp" */; 318 | buildPhases = ( 319 | 9438A1301593E4410042CA60 /* Sources */, 320 | 9438A1311593E4410042CA60 /* Frameworks */, 321 | 9438A1321593E4410042CA60 /* Resources */, 322 | ); 323 | buildRules = ( 324 | ); 325 | dependencies = ( 326 | 9438A1551593E6FD0042CA60 /* PBXTargetDependency */, 327 | ); 328 | name = DemoApp; 329 | productName = DemoApp; 330 | productReference = 9438A1341593E4410042CA60 /* DemoApp.app */; 331 | productType = "com.apple.product-type.application"; 332 | }; 333 | /* End PBXNativeTarget section */ 334 | 335 | /* Begin PBXProject section */ 336 | 9438A0F91593E4110042CA60 /* Project object */ = { 337 | isa = PBXProject; 338 | attributes = { 339 | LastUpgradeCheck = 0440; 340 | ORGANIZATIONNAME = nxtbgthng.com; 341 | }; 342 | buildConfigurationList = 9438A0FC1593E4110042CA60 /* Build configuration list for PBXProject "UITableView+NXEmptyView" */; 343 | compatibilityVersion = "Xcode 3.2"; 344 | developmentRegion = English; 345 | hasScannedForEncodings = 0; 346 | knownRegions = ( 347 | en, 348 | ); 349 | mainGroup = 9438A0F71593E4110042CA60; 350 | productRefGroup = 9438A1071593E4110042CA60 /* Products */; 351 | projectDirPath = ""; 352 | projectRoot = ""; 353 | targets = ( 354 | 9438A1051593E4110042CA60 /* UITableView+NXEmptyView */, 355 | 9438A1131593E4120042CA60 /* UITableView+NXEmptyViewTests */, 356 | 9438A1331593E4410042CA60 /* DemoApp */, 357 | ); 358 | }; 359 | /* End PBXProject section */ 360 | 361 | /* Begin PBXResourcesBuildPhase section */ 362 | 9438A1021593E4110042CA60 /* Resources */ = { 363 | isa = PBXResourcesBuildPhase; 364 | buildActionMask = 2147483647; 365 | files = ( 366 | 9438A10D1593E4110042CA60 /* InfoPlist.strings in Resources */, 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | 9438A1111593E4120042CA60 /* Resources */ = { 371 | isa = PBXResourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | 9438A11E1593E4120042CA60 /* UITableView+NXEmptyView.framework in Resources */, 375 | 9438A1241593E4120042CA60 /* InfoPlist.strings in Resources */, 376 | ); 377 | runOnlyForDeploymentPostprocessing = 0; 378 | }; 379 | 9438A1321593E4410042CA60 /* Resources */ = { 380 | isa = PBXResourcesBuildPhase; 381 | buildActionMask = 2147483647; 382 | files = ( 383 | 9438A13F1593E4410042CA60 /* InfoPlist.strings in Resources */, 384 | 9438A14B1593E4410042CA60 /* NXViewController.xib in Resources */, 385 | ); 386 | runOnlyForDeploymentPostprocessing = 0; 387 | }; 388 | /* End PBXResourcesBuildPhase section */ 389 | 390 | /* Begin PBXShellScriptBuildPhase section */ 391 | 9438A0FE1593E4110042CA60 /* ShellScript */ = { 392 | isa = PBXShellScriptBuildPhase; 393 | buildActionMask = 2147483647; 394 | files = ( 395 | ); 396 | inputPaths = ( 397 | ); 398 | outputPaths = ( 399 | ); 400 | runOnlyForDeploymentPostprocessing = 0; 401 | shellPath = /bin/sh; 402 | shellScript = "set -e\n\nset +u\nif [[ $UFW_MASTER_SCRIPT_RUNNING ]]\nthen\n # Nothing for the slave script to do\n exit 0\nfi\nset -u\n\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]\nthen\n UFW_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\n echo \"Could not find platform name from SDK_NAME: $SDK_NAME\"\n exit 1\nfi\n\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]\nthen\n\tUFW_SDK_VERSION=${BASH_REMATCH[1]}\nelse\n echo \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\n exit 1\nfi\n\nif [[ \"$UFW_SDK_PLATFORM\" = \"iphoneos\" ]]\nthen\n UFW_OTHER_PLATFORM=iphonesimulator\nelse\n UFW_OTHER_PLATFORM=iphoneos\nfi\n\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$UFW_SDK_PLATFORM$ ]]\nthen\n UFW_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${UFW_OTHER_PLATFORM}\"\nelse\n echo \"Could not find $UFW_SDK_PLATFORM in $BUILT_PRODUCTS_DIR\"\n exit 1\nfi\n\n\n# Short-circuit if all binaries are up to date\n\nif [[ -f \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" ]] && \\\n [[ -f \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]] && \\\n [[ ! \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" -nt \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]]\n [[ -f \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" ]] && \\\n [[ -f \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]] && \\\n [[ ! \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" -nt \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]]\nthen\n exit 0\nfi\n\n\n# Clean other platform if needed\n\nif [[ ! -f \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" ]]\nthen\n\techo \"Platform \\\"$UFW_SDK_PLATFORM\\\" was cleaned recently. Cleaning \\\"$UFW_OTHER_PLATFORM\\\" as well\"\n\techo xcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${UFW_OTHER_PLATFORM}${UFW_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" CONFIGURATION_TEMP_DIR=\"${PROJECT_TEMP_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\" clean\n\txcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${UFW_OTHER_PLATFORM}${UFW_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" CONFIGURATION_TEMP_DIR=\"${PROJECT_TEMP_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\" clean\nfi\n\n\n# Make sure we are building from fresh binaries\n\nrm -rf \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\"\nrm -rf \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework\"\nrm -rf \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\"\nrm -rf \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework\"\n"; 403 | }; 404 | 9438A1031593E4110042CA60 /* ShellScript */ = { 405 | isa = PBXShellScriptBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | ); 409 | inputPaths = ( 410 | ); 411 | outputPaths = ( 412 | ); 413 | runOnlyForDeploymentPostprocessing = 0; 414 | shellPath = /bin/sh; 415 | shellScript = "HEADERS_ROOT=$SRCROOT/$PRODUCT_NAME\nFRAMEWORK_HEADERS_DIR=\"$BUILT_PRODUCTS_DIR/$WRAPPER_NAME/Versions/$FRAMEWORK_VERSION/Headers\"\n\n## only header files expected at this point\nPUBLIC_HEADERS=$(find $FRAMEWORK_HEADERS_DIR/. -not -type d 2> /dev/null | sed -e \"s@.*/@@g\")\n\nFIND_OPTS=\"\"\nfor PUBLIC_HEADER in $PUBLIC_HEADERS; do\n if [ -n \"$FIND_OPTS\" ]; then\n FIND_OPTS=\"$FIND_OPTS -o\"\n fi\n FIND_OPTS=\"$FIND_OPTS -name '$PUBLIC_HEADER'\"\ndone\n\nif [ -n \"$FIND_OPTS\" ]; then\n for ORIG_HEADER in $(eval \"find $HEADERS_ROOT/. $FIND_OPTS\" 2> /dev/null | sed -e \"s@^$HEADERS_ROOT/./@@g\"); do\n PUBLIC_HEADER=$(basename $ORIG_HEADER)\n RELATIVE_PATH=$(dirname $ORIG_HEADER)\n if [ -e $FRAMEWORK_HEADERS_DIR/$PUBLIC_HEADER ]; then\n mkdir -p \"$FRAMEWORK_HEADERS_DIR/$RELATIVE_PATH\"\n mv \"$FRAMEWORK_HEADERS_DIR/$PUBLIC_HEADER\" \"$FRAMEWORK_HEADERS_DIR/$RELATIVE_PATH/$PUBLIC_HEADER\"\n fi\n done\nfi\n"; 416 | }; 417 | 9438A1041593E4110042CA60 /* ShellScript */ = { 418 | isa = PBXShellScriptBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | ); 422 | inputPaths = ( 423 | ); 424 | outputPaths = ( 425 | ); 426 | runOnlyForDeploymentPostprocessing = 0; 427 | shellPath = /bin/sh; 428 | shellScript = "set -e\n\nset +u\nif [[ $UFW_MASTER_SCRIPT_RUNNING ]]\nthen\n # Nothing for the slave script to do\n exit 0\nfi\nset -u\nexport UFW_MASTER_SCRIPT_RUNNING=1\n\n\n# Functions\n\n## List files in the specified directory, storing to the specified array.\n#\n# @param $1 The path to list\n# @param $2 The name of the array to fill\n#\n##\nlist_files ()\n{\n filelist=$(ls \"$1\")\n while read line\n do\n eval \"$2[\\${#$2[*]}]=\\\"\\$line\\\"\"\n done <<< \"$filelist\"\n}\n\n\n# Sanity check\n\nif [[ ! -f \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" ]]\nthen\n echo \"Framework target \\\"${TARGET_NAME}\\\" had no source files to build from. Make sure your source files have the correct target membership\"\n exit 1\nfi\n\n\n# Gather information\n\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]\nthen\n UFW_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\n echo \"Could not find platform name from SDK_NAME: $SDK_NAME\"\n exit 1\nfi\n\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]\nthen\n UFW_SDK_VERSION=${BASH_REMATCH[1]}\nelse\n echo \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\n exit 1\nfi\n\nif [[ \"$UFW_SDK_PLATFORM\" = \"iphoneos\" ]]\nthen\n UFW_OTHER_PLATFORM=iphonesimulator\nelse\n UFW_OTHER_PLATFORM=iphoneos\nfi\n\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$UFW_SDK_PLATFORM$ ]]\nthen\n UFW_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${UFW_OTHER_PLATFORM}\"\nelse\n echo \"Could not find $UFW_SDK_PLATFORM in $BUILT_PRODUCTS_DIR\"\n exit 1\nfi\n\n\n# Short-circuit if all binaries are up to date.\n# We already checked the other platform in the prerun script.\n\nif [[ -f \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" ]] && [[ -f \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]] && [[ ! \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" -nt \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/${EXECUTABLE_PATH}\" ]]\nthen\n exit 0\nfi\n\n\n# Make sure the other platform gets built\n\necho \"Build other platform\"\n\necho xcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${UFW_OTHER_PLATFORM}${UFW_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" CONFIGURATION_TEMP_DIR=\"${PROJECT_TEMP_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\" $ACTION\nxcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${UFW_OTHER_PLATFORM}${UFW_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" CONFIGURATION_TEMP_DIR=\"${PROJECT_TEMP_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\" $ACTION\n\n\n# Build the fat static library binary\n\necho \"Create universal static library\"\n\necho \"$PLATFORM_DEVELOPER_BIN_DIR/libtool\" -static \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" -o \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}.temp\"\n\"$PLATFORM_DEVELOPER_BIN_DIR/libtool\" -static \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" \"${UFW_OTHER_BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" -o \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}.temp\"\n\necho mv \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}.temp\" \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\"\nmv \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}.temp\" \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\"\n\n\n# Build framework structure\n\necho \"Build symlinks\"\n\necho ln -sfh A \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Versions/Current\"\nln -sfh A \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Versions/Current\"\necho ln -sfh Versions/Current/Headers \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Headers\"\nln -sfh Versions/Current/Headers \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Headers\"\necho ln -sfh Versions/Current/Resources \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Resources\"\nln -sfh Versions/Current/Resources \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Resources\"\necho ln -sfh \"Versions/Current/${EXECUTABLE_NAME}\" \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${EXECUTABLE_NAME}\"\nln -sfh \"Versions/Current/${EXECUTABLE_NAME}\" \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${EXECUTABLE_NAME}\"\n\n\n# Link to binary for unit tests\n\nmkdir -p \"${BUILT_PRODUCTS_DIR}/.fake_fw_testing.framework\"\nln -sfh \"../${WRAPPER_NAME}/${EXECUTABLE_NAME}\" \"${BUILT_PRODUCTS_DIR}/.fake_fw_testing.framework/.fake_fw_testing\"\n\n\n# Build embedded framework structure\n\necho \"Build Embedded Framework\"\n\necho rm -rf \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework\"\nrm -rf \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework\"\necho mkdir -p \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/Resources\"\nmkdir -p \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/Resources\"\necho cp -a \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/\"\ncp -a \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/\"\n\ndeclare -a UFW_FILE_LIST\nlist_files \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" UFW_FILE_LIST\nfor filename in \"${UFW_FILE_LIST[@]}\"\ndo\n if [[ \"${filename}\" != \"Info.plist\" ]] && [[ ! \"${filename}\" =~ .*\\.lproj$ ]]\n then\n echo ln -sfh \"../${WRAPPER_NAME}/Resources/${filename}\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/Resources/${filename}\"\n ln -sfh \"../${WRAPPER_NAME}/Resources/${filename}\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.embeddedframework/Resources/${filename}\"\n fi\ndone\n\n\n# Replace other platform's framework with a copy of this one (so that both have the same universal binary)\n\necho \"Copy from $UFW_SDK_PLATFORM to $UFW_OTHER_PLATFORM\"\n\necho rm -rf \"${BUILD_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\"\nrm -rf \"${BUILD_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\"\necho cp -a \"${BUILD_DIR}/${CONFIGURATION}-${UFW_SDK_PLATFORM}\" \"${BUILD_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\"\ncp -a \"${BUILD_DIR}/${CONFIGURATION}-${UFW_SDK_PLATFORM}\" \"${BUILD_DIR}/${CONFIGURATION}-${UFW_OTHER_PLATFORM}\"\n"; 429 | }; 430 | 9438A1121593E4120042CA60 /* ShellScript */ = { 431 | isa = PBXShellScriptBuildPhase; 432 | buildActionMask = 2147483647; 433 | files = ( 434 | ); 435 | inputPaths = ( 436 | ); 437 | outputPaths = ( 438 | ); 439 | runOnlyForDeploymentPostprocessing = 0; 440 | shellPath = /bin/sh; 441 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 442 | }; 443 | /* End PBXShellScriptBuildPhase section */ 444 | 445 | /* Begin PBXSourcesBuildPhase section */ 446 | 9438A0FF1593E4110042CA60 /* Sources */ = { 447 | isa = PBXSourcesBuildPhase; 448 | buildActionMask = 2147483647; 449 | files = ( 450 | 9438A1521593E45E0042CA60 /* UITableView+NXEmptyView.m in Sources */, 451 | ); 452 | runOnlyForDeploymentPostprocessing = 0; 453 | }; 454 | 9438A10F1593E4120042CA60 /* Sources */ = { 455 | isa = PBXSourcesBuildPhase; 456 | buildActionMask = 2147483647; 457 | files = ( 458 | 9438A1271593E4120042CA60 /* UITableView_NXEmptyViewTests.m in Sources */, 459 | ); 460 | runOnlyForDeploymentPostprocessing = 0; 461 | }; 462 | 9438A1301593E4410042CA60 /* Sources */ = { 463 | isa = PBXSourcesBuildPhase; 464 | buildActionMask = 2147483647; 465 | files = ( 466 | 9438A1411593E4410042CA60 /* main.m in Sources */, 467 | 9438A1451593E4410042CA60 /* NXAppDelegate.m in Sources */, 468 | 9438A1481593E4410042CA60 /* NXViewController.m in Sources */, 469 | 9405A431162479BA00E83BB5 /* SVPullToRefresh.m in Sources */, 470 | ); 471 | runOnlyForDeploymentPostprocessing = 0; 472 | }; 473 | /* End PBXSourcesBuildPhase section */ 474 | 475 | /* Begin PBXTargetDependency section */ 476 | 9438A11D1593E4120042CA60 /* PBXTargetDependency */ = { 477 | isa = PBXTargetDependency; 478 | target = 9438A1051593E4110042CA60 /* UITableView+NXEmptyView */; 479 | targetProxy = 9438A11C1593E4120042CA60 /* PBXContainerItemProxy */; 480 | }; 481 | 9438A1551593E6FD0042CA60 /* PBXTargetDependency */ = { 482 | isa = PBXTargetDependency; 483 | target = 9438A1051593E4110042CA60 /* UITableView+NXEmptyView */; 484 | targetProxy = 9438A1541593E6FD0042CA60 /* PBXContainerItemProxy */; 485 | }; 486 | /* End PBXTargetDependency section */ 487 | 488 | /* Begin PBXVariantGroup section */ 489 | 9438A10B1593E4110042CA60 /* InfoPlist.strings */ = { 490 | isa = PBXVariantGroup; 491 | children = ( 492 | 9438A10C1593E4110042CA60 /* en */, 493 | ); 494 | name = InfoPlist.strings; 495 | sourceTree = ""; 496 | }; 497 | 9438A1221593E4120042CA60 /* InfoPlist.strings */ = { 498 | isa = PBXVariantGroup; 499 | children = ( 500 | 9438A1231593E4120042CA60 /* en */, 501 | ); 502 | name = InfoPlist.strings; 503 | sourceTree = ""; 504 | }; 505 | 9438A13D1593E4410042CA60 /* InfoPlist.strings */ = { 506 | isa = PBXVariantGroup; 507 | children = ( 508 | 9438A13E1593E4410042CA60 /* en */, 509 | ); 510 | name = InfoPlist.strings; 511 | sourceTree = ""; 512 | }; 513 | 9438A1491593E4410042CA60 /* NXViewController.xib */ = { 514 | isa = PBXVariantGroup; 515 | children = ( 516 | 9438A14A1593E4410042CA60 /* en */, 517 | ); 518 | name = NXViewController.xib; 519 | sourceTree = ""; 520 | }; 521 | /* End PBXVariantGroup section */ 522 | 523 | /* Begin XCBuildConfiguration section */ 524 | 9438A1281593E4120042CA60 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_SEARCH_USER_PATHS = NO; 528 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 529 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 530 | CLANG_ENABLE_OBJC_ARC = YES; 531 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 532 | COPY_PHASE_STRIP = NO; 533 | GCC_C_LANGUAGE_STANDARD = gnu99; 534 | GCC_DYNAMIC_NO_PIC = NO; 535 | GCC_OPTIMIZATION_LEVEL = 0; 536 | GCC_PREPROCESSOR_DEFINITIONS = ( 537 | "DEBUG=1", 538 | "$(inherited)", 539 | ); 540 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 541 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 542 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 543 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 544 | GCC_WARN_UNUSED_VARIABLE = YES; 545 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 546 | SDKROOT = iphoneos; 547 | }; 548 | name = Debug; 549 | }; 550 | 9438A1291593E4120042CA60 /* Release */ = { 551 | isa = XCBuildConfiguration; 552 | buildSettings = { 553 | ALWAYS_SEARCH_USER_PATHS = NO; 554 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 555 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 556 | CLANG_ENABLE_OBJC_ARC = YES; 557 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 558 | COPY_PHASE_STRIP = YES; 559 | GCC_C_LANGUAGE_STANDARD = gnu99; 560 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 561 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 562 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 563 | GCC_WARN_UNUSED_VARIABLE = YES; 564 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 565 | SDKROOT = iphoneos; 566 | VALIDATE_PRODUCT = YES; 567 | }; 568 | name = Release; 569 | }; 570 | 9438A12B1593E4120042CA60 /* Debug */ = { 571 | isa = XCBuildConfiguration; 572 | buildSettings = { 573 | ARCHS = ( 574 | armv6, 575 | "$(inherited)", 576 | ); 577 | CONTENTS_FOLDER_PATH = "$(WRAPPER_NAME)/Versions/$(FRAMEWORK_VERSION)"; 578 | DEAD_CODE_STRIPPING = NO; 579 | DYLIB_COMPATIBILITY_VERSION = 1; 580 | DYLIB_CURRENT_VERSION = 1; 581 | FRAMEWORK_VERSION = A; 582 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 583 | GCC_PREFIX_HEADER = "UITableView+NXEmptyView/UITableView+NXEmptyView-Prefix.pch"; 584 | INFOPLIST_FILE = "UITableView+NXEmptyView/UITableView+NXEmptyView-Info.plist"; 585 | INFOPLIST_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Info.plist"; 586 | INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"; 587 | LINK_WITH_STANDARD_LIBRARIES = NO; 588 | MACH_O_TYPE = mh_object; 589 | OTHER_LDFLAGS = "-ObjC"; 590 | PRODUCT_NAME = "$(TARGET_NAME)"; 591 | SKIP_INSTALL = YES; 592 | UNLOCALIZED_RESOURCES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Resources"; 593 | WRAPPER_EXTENSION = framework; 594 | }; 595 | name = Debug; 596 | }; 597 | 9438A12C1593E4120042CA60 /* Release */ = { 598 | isa = XCBuildConfiguration; 599 | buildSettings = { 600 | ARCHS = ( 601 | armv6, 602 | "$(inherited)", 603 | ); 604 | CONTENTS_FOLDER_PATH = "$(WRAPPER_NAME)/Versions/$(FRAMEWORK_VERSION)"; 605 | DEAD_CODE_STRIPPING = NO; 606 | DYLIB_COMPATIBILITY_VERSION = 1; 607 | DYLIB_CURRENT_VERSION = 1; 608 | FRAMEWORK_VERSION = A; 609 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 610 | GCC_PREFIX_HEADER = "UITableView+NXEmptyView/UITableView+NXEmptyView-Prefix.pch"; 611 | INFOPLIST_FILE = "UITableView+NXEmptyView/UITableView+NXEmptyView-Info.plist"; 612 | INFOPLIST_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Info.plist"; 613 | INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"; 614 | LINK_WITH_STANDARD_LIBRARIES = NO; 615 | MACH_O_TYPE = mh_object; 616 | OTHER_LDFLAGS = "-ObjC"; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SKIP_INSTALL = YES; 619 | UNLOCALIZED_RESOURCES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Resources"; 620 | WRAPPER_EXTENSION = framework; 621 | }; 622 | name = Release; 623 | }; 624 | 9438A12E1593E4120042CA60 /* Debug */ = { 625 | isa = XCBuildConfiguration; 626 | buildSettings = { 627 | FRAMEWORK_SEARCH_PATHS = ( 628 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 629 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 630 | ); 631 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 632 | GCC_PREFIX_HEADER = "UITableView+NXEmptyView/UITableView+NXEmptyView-Prefix.pch"; 633 | HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Libraries"; 634 | INFOPLIST_FILE = "UITableView+NXEmptyViewTests/UITableView+NXEmptyViewTests-Info.plist"; 635 | LIBRARY_SEARCH_PATHS = ( 636 | "$(inherited)", 637 | "\"$(SRCROOT)/Libraries\"", 638 | ); 639 | OTHER_LDFLAGS = ( 640 | "-framework", 641 | SenTestingKit, 642 | "-framework", 643 | .fake_fw_testing, 644 | "-ObjC", 645 | "-force_load", 646 | "${PROJECT_DIR}/Libraries/libOCMock.a", 647 | ); 648 | PRODUCT_NAME = "$(TARGET_NAME)"; 649 | WRAPPER_EXTENSION = octest; 650 | }; 651 | name = Debug; 652 | }; 653 | 9438A12F1593E4120042CA60 /* Release */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | FRAMEWORK_SEARCH_PATHS = ( 657 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 658 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 659 | ); 660 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 661 | GCC_PREFIX_HEADER = "UITableView+NXEmptyView/UITableView+NXEmptyView-Prefix.pch"; 662 | HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Libraries"; 663 | INFOPLIST_FILE = "UITableView+NXEmptyViewTests/UITableView+NXEmptyViewTests-Info.plist"; 664 | LIBRARY_SEARCH_PATHS = ( 665 | "$(inherited)", 666 | "\"$(SRCROOT)/Libraries\"", 667 | ); 668 | OTHER_LDFLAGS = ( 669 | "-framework", 670 | SenTestingKit, 671 | "-framework", 672 | .fake_fw_testing, 673 | "-ObjC", 674 | "-force_load", 675 | "${PROJECT_DIR}/Libraries/libOCMock.a", 676 | ); 677 | PRODUCT_NAME = "$(TARGET_NAME)"; 678 | WRAPPER_EXTENSION = octest; 679 | }; 680 | name = Release; 681 | }; 682 | 9438A14D1593E4410042CA60 /* Debug */ = { 683 | isa = XCBuildConfiguration; 684 | buildSettings = { 685 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 686 | FRAMEWORK_SEARCH_PATHS = ( 687 | "$(inherited)", 688 | "\"$(SYSTEM_APPS_DIR)/Xcode44-DP6.app/Contents/Developer/Library/Frameworks\"", 689 | ); 690 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 691 | GCC_PREFIX_HEADER = "DemoApp/DemoApp-Prefix.pch"; 692 | INFOPLIST_FILE = "DemoApp/DemoApp-Info.plist"; 693 | OTHER_LDFLAGS = ( 694 | "-ObjC", 695 | "-all_load", 696 | "-framework", 697 | "UITableView+NXEmptyView", 698 | ); 699 | PRODUCT_NAME = "$(TARGET_NAME)"; 700 | WRAPPER_EXTENSION = app; 701 | }; 702 | name = Debug; 703 | }; 704 | 9438A14E1593E4410042CA60 /* Release */ = { 705 | isa = XCBuildConfiguration; 706 | buildSettings = { 707 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 708 | FRAMEWORK_SEARCH_PATHS = ( 709 | "$(inherited)", 710 | "\"$(SYSTEM_APPS_DIR)/Xcode44-DP6.app/Contents/Developer/Library/Frameworks\"", 711 | ); 712 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 713 | GCC_PREFIX_HEADER = "DemoApp/DemoApp-Prefix.pch"; 714 | INFOPLIST_FILE = "DemoApp/DemoApp-Info.plist"; 715 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 716 | OTHER_LDFLAGS = ( 717 | "-ObjC", 718 | "-all_load", 719 | "-framework", 720 | "UITableView+NXEmptyView", 721 | ); 722 | PRODUCT_NAME = "$(TARGET_NAME)"; 723 | WRAPPER_EXTENSION = app; 724 | }; 725 | name = Release; 726 | }; 727 | /* End XCBuildConfiguration section */ 728 | 729 | /* Begin XCConfigurationList section */ 730 | 9438A0FC1593E4110042CA60 /* Build configuration list for PBXProject "UITableView+NXEmptyView" */ = { 731 | isa = XCConfigurationList; 732 | buildConfigurations = ( 733 | 9438A1281593E4120042CA60 /* Debug */, 734 | 9438A1291593E4120042CA60 /* Release */, 735 | ); 736 | defaultConfigurationIsVisible = 0; 737 | defaultConfigurationName = Release; 738 | }; 739 | 9438A12A1593E4120042CA60 /* Build configuration list for PBXNativeTarget "UITableView+NXEmptyView" */ = { 740 | isa = XCConfigurationList; 741 | buildConfigurations = ( 742 | 9438A12B1593E4120042CA60 /* Debug */, 743 | 9438A12C1593E4120042CA60 /* Release */, 744 | ); 745 | defaultConfigurationIsVisible = 0; 746 | defaultConfigurationName = Release; 747 | }; 748 | 9438A12D1593E4120042CA60 /* Build configuration list for PBXNativeTarget "UITableView+NXEmptyViewTests" */ = { 749 | isa = XCConfigurationList; 750 | buildConfigurations = ( 751 | 9438A12E1593E4120042CA60 /* Debug */, 752 | 9438A12F1593E4120042CA60 /* Release */, 753 | ); 754 | defaultConfigurationIsVisible = 0; 755 | defaultConfigurationName = Release; 756 | }; 757 | 9438A14C1593E4410042CA60 /* Build configuration list for PBXNativeTarget "DemoApp" */ = { 758 | isa = XCConfigurationList; 759 | buildConfigurations = ( 760 | 9438A14D1593E4410042CA60 /* Debug */, 761 | 9438A14E1593E4410042CA60 /* Release */, 762 | ); 763 | defaultConfigurationIsVisible = 0; 764 | defaultConfigurationName = Release; 765 | }; 766 | /* End XCConfigurationList section */ 767 | }; 768 | rootObject = 9438A0F91593E4110042CA60 /* Project object */; 769 | } 770 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView/UITableView+NXEmptyView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.nxtbgthng.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView/UITableView+NXEmptyView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'UITableView+NXEmptyView' target in the 'UITableView+NXEmptyView' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView/UITableView+NXEmptyView.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+NXEmptyView.h 3 | // TableWithEmptyView 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface UITableView (NXEmptyView) 12 | 13 | @property (nonatomic, strong) IBOutlet UIView *nxEV_emptyView; 14 | @property (nonatomic, assign) BOOL nxEV_hideSeparatorLinesWhenShowingEmptyView; 15 | 16 | @end 17 | 18 | 19 | @protocol UITableViewNXEmptyViewDataSource 20 | @optional 21 | - (BOOL)tableViewShouldBypassNXEmptyView:(UITableView *)tableView; 22 | @end 23 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView/UITableView+NXEmptyView.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+NXEmptyView.m 3 | // TableWithEmptyView 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "UITableView+NXEmptyView.h" 12 | 13 | 14 | static const NSString *NXEmptyViewAssociatedKey = @"NXEmptyViewAssociatedKey"; 15 | static const NSString *NXEmptyViewHideSeparatorLinesAssociatedKey = @"NXEmptyViewHideSeparatorLinesAssociatedKey"; 16 | static const NSString *NXEmptyViewPreviousSeparatorStyleAssociatedKey = @"NXEmptyViewPreviousSeparatorStyleAssociatedKey"; 17 | 18 | 19 | void nxEV_swizzle(Class c, SEL orig, SEL new) 20 | { 21 | Method origMethod = class_getInstanceMethod(c, orig); 22 | Method newMethod = class_getInstanceMethod(c, new); 23 | if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) 24 | class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 25 | else 26 | method_exchangeImplementations(origMethod, newMethod); 27 | } 28 | 29 | 30 | 31 | @interface UITableView (NXEmptyViewPrivate) 32 | @property (nonatomic, assign) UITableViewCellSeparatorStyle nxEV_previousSeparatorStyle; 33 | @end 34 | 35 | 36 | @implementation UITableView (NXEmptyView) 37 | 38 | #pragma mark Entry 39 | 40 | + (void)load; 41 | { 42 | Class c = [UITableView class]; 43 | nxEV_swizzle(c, @selector(reloadData), @selector(nxEV_reloadData)); 44 | nxEV_swizzle(c, @selector(layoutSubviews), @selector(nxEV_layoutSubviews)); 45 | } 46 | 47 | #pragma mark Properties 48 | 49 | - (BOOL)nxEV_hasRowsToDisplay; 50 | { 51 | NSUInteger numberOfRows = 0; 52 | for (NSInteger sectionIndex = 0; sectionIndex < self.numberOfSections; sectionIndex++) { 53 | numberOfRows += [self numberOfRowsInSection:sectionIndex]; 54 | } 55 | return (numberOfRows > 0); 56 | } 57 | 58 | @dynamic nxEV_emptyView; 59 | - (UIView *)nxEV_emptyView; 60 | { 61 | return objc_getAssociatedObject(self, &NXEmptyViewAssociatedKey); 62 | } 63 | 64 | - (void)setNxEV_emptyView:(UIView *)value; 65 | { 66 | if (self.nxEV_emptyView.superview) { 67 | [self.nxEV_emptyView removeFromSuperview]; 68 | } 69 | objc_setAssociatedObject(self, &NXEmptyViewAssociatedKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 70 | [self nxEV_updateEmptyView]; 71 | } 72 | 73 | @dynamic nxEV_hideSeparatorLinesWhenShowingEmptyView; 74 | - (BOOL)nxEV_hideSeparatorLinesWhenShowingEmptyView 75 | { 76 | NSNumber *hideSeparator = objc_getAssociatedObject(self, &NXEmptyViewHideSeparatorLinesAssociatedKey); 77 | return hideSeparator ? [hideSeparator boolValue] : NO; 78 | } 79 | 80 | - (void)setNxEV_hideSeparatorLinesWhenShowingEmptyView:(BOOL)value 81 | { 82 | NSNumber *hideSeparator = [NSNumber numberWithBool:value]; 83 | objc_setAssociatedObject(self, &NXEmptyViewHideSeparatorLinesAssociatedKey, hideSeparator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 84 | } 85 | 86 | 87 | #pragma mark Updating 88 | 89 | - (void)nxEV_updateEmptyView; 90 | { 91 | UIView *emptyView = self.nxEV_emptyView; 92 | 93 | if (!emptyView) return; 94 | 95 | if (emptyView.superview != self) { 96 | [self addSubview:emptyView]; 97 | } 98 | 99 | // setup empty view frame 100 | CGRect frame = self.bounds; 101 | frame.origin = CGPointMake(0, 0); 102 | frame = UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(CGRectGetHeight(self.tableHeaderView.frame), 0, 0, 0)); 103 | frame.size.height -= self.contentInset.top; 104 | emptyView.frame = frame; 105 | emptyView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth); 106 | 107 | // check available data 108 | BOOL emptyViewShouldBeShown = (self.nxEV_hasRowsToDisplay == NO); 109 | 110 | // check bypassing 111 | if (emptyViewShouldBeShown && [self.dataSource respondsToSelector:@selector(tableViewShouldBypassNXEmptyView:)]) { 112 | BOOL emptyViewShouldBeBypassed = [(id)self.dataSource tableViewShouldBypassNXEmptyView:self]; 113 | emptyViewShouldBeShown &= !emptyViewShouldBeBypassed; 114 | } 115 | 116 | // hide tableView separators, if present 117 | if (self.nxEV_hideSeparatorLinesWhenShowingEmptyView) { 118 | if (emptyViewShouldBeShown) { 119 | if (self.separatorStyle != UITableViewCellSeparatorStyleNone) { 120 | self.nxEV_previousSeparatorStyle = self.separatorStyle; 121 | self.separatorStyle = UITableViewCellSeparatorStyleNone; 122 | } 123 | } else { 124 | if (self.separatorStyle != self.nxEV_previousSeparatorStyle) { 125 | // we've seen an issue with the separator color not being correct when setting separator style during layoutSubviews 126 | // that's why we schedule the call on the next runloop cycle 127 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 128 | self.separatorStyle = self.nxEV_previousSeparatorStyle; 129 | }); 130 | 131 | } 132 | } 133 | } 134 | 135 | // show / hide empty view 136 | emptyView.hidden = !emptyViewShouldBeShown; 137 | } 138 | 139 | 140 | #pragma mark Swizzle methods 141 | 142 | - (void)nxEV_reloadData; 143 | { 144 | // this calls the original reloadData implementation 145 | [self nxEV_reloadData]; 146 | 147 | [self nxEV_updateEmptyView]; 148 | } 149 | 150 | - (void)nxEV_layoutSubviews; 151 | { 152 | // this calls the original layoutSubviews implementation 153 | [self nxEV_layoutSubviews]; 154 | 155 | [self nxEV_updateEmptyView]; 156 | } 157 | 158 | @end 159 | 160 | 161 | #pragma mark Private 162 | #pragma mark - 163 | 164 | @implementation UITableView (NXEmptyViewPrivate) 165 | 166 | @dynamic nxEV_previousSeparatorStyle; 167 | - (UITableViewCellSeparatorStyle)nxEV_previousSeparatorStyle 168 | { 169 | NSNumber *previousSeparatorStyle = objc_getAssociatedObject(self, &NXEmptyViewPreviousSeparatorStyleAssociatedKey); 170 | return previousSeparatorStyle ? [previousSeparatorStyle intValue] : self.separatorStyle; 171 | } 172 | 173 | - (void)setNxEV_previousSeparatorStyle:(UITableViewCellSeparatorStyle)value 174 | { 175 | NSNumber *previousSeparatorStyle = [NSNumber numberWithInt:value]; 176 | objc_setAssociatedObject(self, &NXEmptyViewPreviousSeparatorStyleAssociatedKey, previousSeparatorStyle, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /UITableView+NXEmptyView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /UITableView+NXEmptyViewTests/UITableView+NXEmptyViewTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.nxtbgthng.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /UITableView+NXEmptyViewTests/UITableView_NXEmptyViewTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView_NXEmptyViewTests.h 3 | // UITableView+NXEmptyViewTests 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | @interface UITableView_NXEmptyViewTests : SenTestCase 15 | 16 | @property (nonatomic, retain) UITableView *tableView; 17 | @property (nonatomic, retain) OCMockObject *dataSourceMock; 18 | 19 | @property (nonatomic, retain) NSArray *dataSourceItems; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /UITableView+NXEmptyViewTests/UITableView_NXEmptyViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView_NXEmptyViewTests.m 3 | // UITableView+NXEmptyViewTests 4 | // 5 | // Created by Ullrich Schäfer on 21.06.12. 6 | // Copyright (c) 2012 nxtbgthng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "UITableView_NXEmptyViewTests.h" 13 | 14 | @implementation UITableView_NXEmptyViewTests 15 | 16 | - (void)setUp 17 | { 18 | [super setUp]; 19 | 20 | self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) style:UITableViewStylePlain]; 21 | self.tableView.nxEV_emptyView = [[UIView alloc] initWithFrame:CGRectZero]; 22 | 23 | self.dataSourceMock = [OCMockObject niceMockForProtocol:@protocol(UITableViewNXEmptyViewDataSource)]; 24 | self.tableView.dataSource = self.dataSourceMock; 25 | 26 | // configuring the database mock 27 | UITableViewCell *dummyCell = [OCMockObject niceMockForClass:[UITableViewCell class]]; 28 | NSInteger sections = 1; // this needs to be in a seperate variable for OCMOCK_VALUE to work 29 | 30 | [[[self.dataSourceMock stub] andReturn:dummyCell] tableView:OCMOCK_ANY cellForRowAtIndexPath:OCMOCK_ANY]; 31 | [[[self.dataSourceMock stub] andReturnValue:OCMOCK_VALUE(sections)] numberOfSectionsInTableView:OCMOCK_ANY]; 32 | 33 | // dynamically get the number of rows from dataSourceItems 34 | __block id blockSelf = self; 35 | void(^numberOfRowsBlock)(NSInvocation *) = ^(NSInvocation *i) { 36 | NSInteger rowCount = [[blockSelf dataSourceItems] count]; 37 | [i setReturnValue:&rowCount]; 38 | }; 39 | [[[self.dataSourceMock stub] andDo:numberOfRowsBlock] tableView:OCMOCK_ANY numberOfRowsInSection:0]; 40 | } 41 | 42 | - (void)tearDown 43 | { 44 | self.tableView = nil; 45 | self.dataSourceMock = nil; 46 | [super tearDown]; 47 | } 48 | 49 | #pragma mark - 50 | #pragma mark Tests 51 | 52 | - (void)testTheMocking 53 | { 54 | self.dataSourceItems = [NSArray arrayWithObject:@"x"]; 55 | [self.tableView reloadData]; 56 | STAssertEquals([self.tableView numberOfRowsInSection:0], 1, @"Better check the mocking of the tests (1)"); 57 | 58 | self.dataSourceItems = [NSArray array]; 59 | [self.tableView reloadData]; 60 | STAssertEquals([self.tableView numberOfRowsInSection:0], 0, @"Better check the mocking of the tests (2)"); 61 | } 62 | 63 | - (void)testForNilEmptyView 64 | { 65 | self.dataSourceItems = [NSArray arrayWithObject:@"x"]; 66 | [self.tableView reloadData]; 67 | STAssertTrue([self.tableView numberOfRowsInSection:0] > 0, @"There should be cells in the table view"); 68 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 69 | STAssertNil(self.tableView.nxEV_emptyView.superview, @"The empty view should not be visible"); 70 | } 71 | 72 | - (void)testForEmptyView 73 | { 74 | self.dataSourceItems = [NSArray array]; 75 | [self.tableView reloadData]; 76 | STAssertTrue([self.tableView numberOfRowsInSection:0] == 0, @"There should be no cells in the table view"); 77 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 78 | STAssertNotNil(self.tableView.nxEV_emptyView.superview, @"The empty view should be visible"); 79 | } 80 | 81 | - (void)testThatTheFrameOfTheEmptyViewIsSetCorrectly 82 | { 83 | [self.tableView reloadData]; 84 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 85 | STAssertNotNil(self.tableView.nxEV_emptyView.superview, @"The empty view should be visible"); 86 | STAssertTrue(CGRectEqualToRect(self.tableView.nxEV_emptyView.frame, self.tableView.bounds), @"The frame of the emptyView should be the bounds of the table view"); 87 | } 88 | 89 | - (void)testThatTheFrameOfTheEmptyViewIsUpdatedTogetherWithTheTableView 90 | { 91 | [self.tableView reloadData]; 92 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 93 | STAssertNotNil(self.tableView.nxEV_emptyView.superview, @"The empty view should be visible"); 94 | STAssertTrue(CGRectEqualToRect(self.tableView.nxEV_emptyView.frame, self.tableView.bounds), @"The frame of the emptyView should be the bounds of the table view"); 95 | self.tableView.frame = CGRectMake(10, 10, 200, 200); 96 | STAssertTrue(CGRectEqualToRect(self.tableView.nxEV_emptyView.frame, self.tableView.bounds), @"The frame of the emptyView should be the bounds of the table view, even after updating and not %@", NSStringFromCGRect(self.tableView.nxEV_emptyView.frame)); 97 | } 98 | 99 | - (void)testBypassingOfTheEmptyView 100 | { 101 | [self.tableView reloadData]; 102 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 103 | STAssertNotNil(self.tableView.nxEV_emptyView.superview, @"The empty view should be visible"); 104 | 105 | BOOL shouldBypassEmptyView = YES; 106 | [[[self.dataSourceMock stub] andReturnValue:OCMOCK_VALUE(shouldBypassEmptyView)] tableViewShouldBypassNXEmptyView:OCMOCK_ANY]; 107 | [self.tableView reloadData]; 108 | 109 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 110 | STAssertNil(self.tableView.nxEV_emptyView.superview, @"The empty view should not be visible"); 111 | } 112 | 113 | - (void)testTableViewShouldStillWorkWithDefaultDatasourceProtocol 114 | { 115 | id plainDataSource = [OCMockObject niceMockForProtocol:@protocol(UITableViewDataSource)]; 116 | [[[plainDataSource stub] andReturnValue:[NSNumber numberWithInteger:0]] tableView:OCMOCK_ANY numberOfRowsInSection:0]; 117 | self.tableView.dataSource = plainDataSource; 118 | [self.tableView reloadData]; 119 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 120 | STAssertNotNil(self.tableView.nxEV_emptyView.superview, @"The empty view should be visible"); 121 | } 122 | 123 | - (void)testEmptyViewShouldScrollWithTableView 124 | { 125 | [self.tableView reloadData]; 126 | STAssertNotNil(self.tableView.nxEV_emptyView, @"There should be an empty view"); 127 | STAssertTrue(CGPointEqualToPoint(self.tableView.nxEV_emptyView.frame.origin, CGPointZero), @"Empty view should be positioned correctly"); 128 | 129 | [self.tableView setContentOffset:CGPointMake(0, 40)]; 130 | // needs the layout subviews here, because setContentOffset is just calling setNeedsLayout and we don't want 131 | // to add asynchrony to the test :) 132 | [self.tableView layoutSubviews]; 133 | 134 | STAssertTrue(CGPointEqualToPoint(self.tableView.nxEV_emptyView.frame.origin, CGPointZero), @"Empty view should be positioned correctly"); 135 | } 136 | 137 | - (void)testTableViewShouldNotHideSeparatorLinesWhenShowingEmptyView 138 | { 139 | self.dataSourceItems = [NSArray arrayWithObject:@"x"]; 140 | [self.tableView reloadData]; 141 | UITableViewCellSeparatorStyle separatorStyle = self.tableView.separatorStyle; 142 | 143 | STAssertTrue(self.tableView.separatorStyle == UITableViewCellSeparatorStyleSingleLine, @"Default separator style should be present"); 144 | 145 | self.dataSourceItems = [NSArray array]; 146 | [self.tableView reloadData]; 147 | 148 | STAssertTrue(self.tableView.separatorStyle == separatorStyle, @"Separator style should not change when empty view is shown"); 149 | } 150 | 151 | - (void)testTableViewShouldHideSeparatorLinesWhenShowingEmptyViewWhenRequested 152 | { 153 | self.tableView.nxEV_hideSeparatorLinesWhenShowingEmptyView = YES; 154 | 155 | self.dataSourceItems = [NSArray arrayWithObject:@"x"]; 156 | [self.tableView reloadData]; 157 | UITableViewCellSeparatorStyle separatorStyle = self.tableView.separatorStyle; 158 | 159 | self.dataSourceItems = [NSArray array]; 160 | [self.tableView reloadData]; 161 | 162 | STAssertTrue(self.tableView.separatorStyle == UITableViewCellSeparatorStyleNone, @"Separator should be hidden"); 163 | 164 | self.dataSourceItems = [NSArray arrayWithObject:@"x"]; 165 | [self.tableView reloadData]; 166 | 167 | STAssertTrue(self.tableView.separatorStyle == separatorStyle, @"Separator should reappear"); 168 | } 169 | 170 | - (void)testEmptyViewShouldRespectTableHeaderView 171 | { 172 | [self.tableView reloadData]; 173 | self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)]; 174 | [self.tableView layoutSubviews]; 175 | 176 | STAssertTrue(CGPointEqualToPoint(self.tableView.nxEV_emptyView.frame.origin, CGPointMake(0, 50)), @"Empty view should be positioned correctly"); 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /UITableView+NXEmptyViewTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /UITableView-NXEmptyView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'UITableView-NXEmptyView' 3 | s.platform = :ios 4 | s.version = '0.1.7' 5 | s.license = 'BSD' 6 | s.summary = 'A category on UITableView that adds an empty view that can be shown whenever the table view has no cells.' 7 | s.homepage = 'https://github.com/nxtbgthng/UITableView-NXEmptyView' 8 | s.author = { 'nxtbgthng' => 'team@nxtbgthng.com'} 9 | s.source = { :git => 'https://github.com/nxtbgthng/UITableView-NXEmptyView.git', 10 | :tag => "v#{s.version}" } 11 | s.source_files = 'UITableView+NXEmptyView/UITableView+NXEmptyView.h', 'UITableView+NXEmptyView/UITableView+NXEmptyView.m' 12 | s.frameworks = 'UIKit' 13 | s.requires_arc = true 14 | end 15 | --------------------------------------------------------------------------------