为什么 numberOfRowsInSections: 方法被调用了 5 次?而 numberOfSections 的 6 倍?
Why the numberOfRowsInSections: method is invoked 5 times ? And the numberOfSections 6 times?
我再次发布这个问题,这个问题已经在这个主题中被问到了:
When is tableView:numberOfRowsInSection: called in UITableView?
我正在学习 Big Nerd Ranch 课程,我的程序中似乎调用了 5 次此方法,我不明白为什么...
它在 viewDidLoad 之后调用,甚至在初始化之后调用。但是它在 tableView:cellForRowAtIndexPath: 方法被调用之前被调用。
我在我的代码中到处都设置了断点,也到处都设置了 NSLogs(我在我的代码中删除了一些断点以使其更清晰),但我仍然不知道每次调用它之间发生了什么。
这是我的代码:
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:
什么鬼?
superclass(UITableView / Controller)不缓存那些值,这是一件好事:你不告诉superclass,当数字改变时,它不得不问。这与 Apple 选择的白盒方法一致。
因此,每当 Apple 的 superclass 实现中的算法需要知道这些值时,它就必须调用。当 Apple 更改某些算法时,调用次数可能会发生变化。我不会想太多。没有错。
唯一的结论:尽可能便宜地实施这些方法。
我再次发布这个问题,这个问题已经在这个主题中被问到了: When is tableView:numberOfRowsInSection: called in UITableView?
我正在学习 Big Nerd Ranch 课程,我的程序中似乎调用了 5 次此方法,我不明白为什么... 它在 viewDidLoad 之后调用,甚至在初始化之后调用。但是它在 tableView:cellForRowAtIndexPath: 方法被调用之前被调用。 我在我的代码中到处都设置了断点,也到处都设置了 NSLogs(我在我的代码中删除了一些断点以使其更清晰),但我仍然不知道每次调用它之间发生了什么。
这是我的代码:
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: 什么鬼?
superclass(UITableView / Controller)不缓存那些值,这是一件好事:你不告诉superclass,当数字改变时,它不得不问。这与 Apple 选择的白盒方法一致。
因此,每当 Apple 的 superclass 实现中的算法需要知道这些值时,它就必须调用。当 Apple 更改某些算法时,调用次数可能会发生变化。我不会想太多。没有错。
唯一的结论:尽可能便宜地实施这些方法。