为什么numberOfRowsInSections:方法被调用5次? 而这个数字是6次?

我再次发布这个问题,这个问题已经在这个主题已经被问: 当tableView:numberOfRowsInSection:在UITableView中调用?

我正在遵循Big Nerd Ranch课程,看来这个方法在我的程序中被调用了5次,我不明白为什么…它在viewDidLoad之后,甚至在初始化之后被调用。 但是在调用tableView:cellForRowAtIndexPath:方法之前调用它。 我把代码中的断点放到了我的代码中,而且NSLog也到处都是(我在代码中删除了一些代码,以使它更清晰),但是我仍然不知道每次调用之间会发生什么。

这是我的代码:

BNRAppDelegate.h

#import <UIKit/UIKit.h> @interface BNRAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end 

BNRAppDelegate.m

 #import "BNRAppDelegate.h" #import "BNRItemsViewController.h" @interface BNRAppDelegate () @end @implementation BNRAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. //Create a BNRItemsViewController BNRItemsViewController *itemsViewController = [[BNRItemsViewController alloc] init]; //Place BNRItemsViewController's table view in the window hierarchy self.window.rootViewController = itemsViewController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; } //etc... @end 

BNRItem.h

 #import <Foundation/Foundation.h> @interface BNRItem : NSObject { NSString *_itemName; NSString *_serialNumber; int _valueInDollars; NSDate *_dateCreated; } @property NSString *itemName; @property NSString *serialNumber; @property int valueInDollars; @property NSDate *dateCreated; +(instancetype)randomItem; //Designated initializer for BNRItem -(instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber; -(instancetype)initWithItemName:(NSString *)name; @end 

BNRItem.m

 #import "BNRItem.h" @implementation BNRItem +(instancetype)randomItem { //Create an immutable array of three adjectives NSArray *randomAdjectiveList = @[@"Fluffy", @"Rusty", @"Shiny"]; //Create an immutable array of three nouns NSArray *randomNounList = @[@"Bear", @"Spork", @"Mac"]; //Get the index of a random adjective/noun from the lists //Note: the % operator, called the modulo operator, gives you the remainder. So adjectiveIndex is a random number from 0 to 2 inclusive. NSInteger adjectiveIndex = arc4random() % [randomAdjectiveList count]; NSInteger nounIndex = arc4random() % [randomNounList count]; //Note the NSInteger is not an object but a type definition for "long" NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]]; int randomValue = arc4random() % 100; NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c", '0' + arc4random() % 10, 'A' + arc4random() % 26, '0' + arc4random() % 10, 'A' + arc4random() % 26, '0' + arc4random() % 10]; BNRItem *newItem = [[self alloc] initWithItemName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber]; return newItem; } -(instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber { //Call the superclass's designated initializer self = [super init]; //Did the superclass's designated initializer succeed? if (self) { //Give the instance variables initial values self.itemName = name; self.serialNumber = sNumber; self.valueInDollars = value; //Set _dateCreated to the current date and time self.dateCreated = [[NSDate alloc] init]; } //Return the address of the newly initialized object return self; } -(instancetype)initWithItemName:(NSString *)name { return [self initWithItemName:name valueInDollars:0 serialNumber:@""]; } -(instancetype)init { return [self initWithItemName:@"Item"]; } -(NSString *)description { NSString *descritptionString = [[NSString alloc] initWithFormat:@"%@ (%@): worth $%d, recorded on %@", self.itemName, self.serialNumber, self.valueInDollars, self.dateCreated]; return descritptionString; } @end 

BNRItemStore.h

 #import <Foundation/Foundation.h> @class BNRItem; @interface BNRItemStore : NSObject @property (nonatomic, readonly) NSArray *allItems; +(instancetype)sharedStore; -(BNRItem *)createItem; @end 

BNRItemStore.m

 #import "BNRItemStore.h" #import "BNRItem.h" @interface BNRItemStore () @property (nonatomic) NSMutableArray *privateItems; @end @implementation BNRItemStore +(instancetype)sharedStore { static BNRItemStore *sharedStore = nil; //Do I need to create a sharedStore ? if (!sharedStore) { sharedStore = [[self alloc] initPrivate]; } return sharedStore; } //If a programmer calls [[BNRItemsStore alloc] init], let him know the error of his ways -(instancetype)init { @throw [NSException exceptionWithName:@"Singleton" reason:@"Use +[BNRItemStore sharedStore]" userInfo:nil]; return nil; } //Here is the real (secret) intializer -(instancetype)initPrivate { self = [super init]; if (self) { _privateItems = [[NSMutableArray alloc] init]; } return self; } -(NSArray *)allItems { return self.privateItems; } -(BNRItem *)createItem { BNRItem *item = [BNRItem randomItem]; [self.privateItems addObject:item]; return item; } @end 

BNRItemsViewController.h

 #import <UIKit/UIKit.h> #import "BNRItemsViewController.h" #import "BNRItemStore.h" #import "BNRItem.h" @interface BNRItemsViewController : UITableViewController @property (nonatomic) BNRItemStore *itemStore; @end 

BNRItemsViewController.m

 #import "BNRItemsViewController.h" #import "BNRItemStore.h" #import "BNRItem.h" @implementation BNRItemsViewController -(BNRItemStore *)itemStore { BNRItemStore *itemStore = [BNRItemStore sharedStore]; return itemStore; } //Designated Initializer is initWithStyle Changing to init -(instancetype)init { //ALWAYS call the superclass's designated initializer self = [super initWithStyle:UITableViewStylePlain]; if (self) { for (int i = 0; i < 8; i++) { BNRItem *item = [self.itemStore createItem]; NSLog(@"The %@, valued %d has been created. It is at index %lud", item.itemName, item.valueInDollars, (unsigned long)[[[BNRItemStore sharedStore] allItems] indexOfObject:item]); } } return self; } -(instancetype)initWithStyle:(UITableViewStyle)style { return [self init]; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"This tableview has %ld section and %lu rows", (long)section, (unsigned long)[[self.itemStore allItems] count]); return [[self.itemStore allItems] count]; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Get a new or recycled cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; //Set the text on the cell with the description of the item that is at the nth index of items, where n = row this cell will appear in on the tableview NSArray *items = [self.itemStore allItems]; BNRItem *item = items[indexPath.row]; NSLog(@"%@ is in indexPath %ld - %ld", item.itemName, (long)[indexPath section], (long)[indexPath row]); cell.textLabel.text = [item description]; return cell; } -(void)viewDidLoad { [super viewDidLoad]; NSLog(@"ViewDidLoad1"); [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; NSLog(@"ViewDidLoad2"); } @end 

我也有另外的代码,我有2个部分,所以我调用的方法numberOfSections :,这个被称为6倍! 先连续两次,然后用numberOfRowsInSection替代:这到底是什么?

超类(UITableView / Controller)不caching这些值,这是一件好事:你不告诉超类,当数字发生了变化时,必须要求。 这与苹果select的白盒方法一致。

所以无论何时在Apples超类实现中的algorithm需要知道这些值,它都必须调用。 而当苹果改变一些algorithm,呼叫的数量可能会改变。 我不会推翻这一点。 没有任何错误。

唯一的结论是:尽可能便宜地实施这些方法。