自定义 UITableView 的意外行为

Posted

技术标签:

【中文标题】自定义 UITableView 的意外行为【英文标题】:Unexpected behavior with custom UITableView 【发布时间】:2011-03-31 22:01:53 【问题描述】:

我正在创建一个实现自定义 UITableView 的应用程序。我这样做的方式如下:

我创建了一个 UINavigationController。这个 UINavigationController 推送一个实现 UITableViewDelegate 和 UITableViewDataSource 的 UIViewController。我为此 UIViewController 创建了一个 .xib,因此 UIViewController 有 3 个文件:TestTableViewController.h、TestTableViewController.m 和 TestTableViewController.xib。

TestTableViewController.xib 中只有一个 UITableView 与名为 testTableView 的 IBOutlet UITableView 相关联,并且此 UITableView 数据源和委托与文件的所有者(TestTableViewController)相关联。

另外,我已经实现了自定义 UITableViewCell。我创建了一个名为 TestCell.xib 的空 .xib,我在其中放置了一个 UITableViewCell 并插入了一个 UIView、一个 UILabel、一个 UIImageView 和一个 UISwitch。然后我创建了一个继承自 UITableViewCell 的类,如下所示(我将 TestCell.xib 的视图定义为 TestCell 类并将标识符设置为 TestCellIdentifier):

TestCell.h:

#import <UIKit/UIKit.h>

#define kTestHeight 40


@interface TestCell : UITableViewCell 
    UIImageView *testImage;
    UILabel *testLabel;


@property (nonatomic, retain) IBOutlet UIImageView *testImage;
@property (nonatomic, retain) IBOutlet UILabel *testLabel;

@end

TestCell.m:

#import "TestCell.h"


@implementation TestCell

@synthesize testImage, testLabel;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) 
        // Initialization code
    
    return self;


- (void)setSelected:(BOOL)selected animated:(BOOL)animated

    [super setSelected:selected animated:animated];

    // Configure the view for the selected state


- (void)dealloc

    [self.testLabel release];
    [self.testImage release];
    [super dealloc];


@end

我实现了所有的TestTableViewController如下:

TestTableViewController.h:

#import <UIKit/UIKit.h>


@interface TestTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> 
    NSArray *labels;
    NSArray *images;
    UITableView *testTableView; // this is the UITableView linked in the NIB


@property (nonatomic, retain) NSArray *labels, *images;
@property (nonatomic, retain) IBOutlet UITableView *testTableView;

@end

TestTableViewController.m:

#import "TestTableViewController.h"
#import "TestCell.h"


@implementation TestTableViewController

@synthesize labels, images;
@synthesize testTableView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)dealloc

    [self.labels release];
    [self.images release];
    [self.testTableView release];
    [super dealloc];


- (void)didReceiveMemoryWarning

    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.


#pragma mark - View lifecycle

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"Test";
    self.labels = [[NSArray alloc] initWithObjects:
                    @"Test 1",
                    @"Test 2",
                    @"Test 3", 
                    @"Test 4",
                    @"Test 5",
                    @"Test 6",
                    @"Test 7",
                    @"Test 8",
                    @"Test 9",
                    @"Test 10",
                    @"Test 11",
                    @"Test 12",
                    @"Test 13",
                    @"Test 14",
                    @"Test 15",
                    @"Test 16",
                    @"Test 17", nil];
    self.images = [[NSArray alloc] initWithObjects:
                         [UIImage imageNamed:@"empty1.png"],
                         [UIImage imageNamed:@"empty2.png"],
                         [UIImage imageNamed:@"empty3.png"],
                         [UIImage imageNamed:@"empty4.png"],
                         [UIImage imageNamed:@"empty5.png"],
                         [UIImage imageNamed:@"empty6.png"],
                         [UIImage imageNamed:@"empty7.png"],
                         [UIImage imageNamed:@"empty8.png"],
                         [UIImage imageNamed:@"empty9.png"],
                         [UIImage imageNamed:@"empty10.png"],
                         [UIImage imageNamed:@"empty11.png"],
                         [UIImage imageNamed:@"empty12.png"],
                         [UIImage imageNamed:@"empty13.png"],
                         [UIImage imageNamed:@"empty14.png"],
                         [UIImage imageNamed:@"empty15.png"],
                         [UIImage imageNamed:@"empty16.png"],
                         [UIImage imageNamed:@"empty17.png"], nil];
    self.testTableView.separatorColor = [UIColor colorWithRed:0 green:0.21 blue:0.43 alpha:1];


- (void)viewDidUnload

    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.labels = nil;
    self.images = nil;
    self.testTableView = nil;


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);


#pragma mark - Table view data source methods

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    // Return the cell's height
    return kTestCellHeight;


-  (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

    return [self.labels count];


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *TestCellIdentifier = @"TestCellIdentifier";

    TestCell *cell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:TestCellIdentifier];
    if (cell == nil) 
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"TestCell" 
                                                     owner:self 
                                                   options:nil];
        for (id oneObject in nib) 
            if ([oneObject isKindOfClass:[TestCell class]]) 
                cell = (TestCell *)oneObject;
            
        
    

    NSInteger row = [indexPath row];
    cell.testLabel.text = [self.labels objectAtIndex:row];
    cell.testImage.image = [self.images objectAtIndex:row];

    return cell;


@end

我想这就是所需的上下文描述。现在的问题。当我将表中的一个开关设置为 OFF(默认情况下它们为 ON)然后向下滚动然后再次向上滚动时,表开始将随机开关调整为 OFF 和 ON。这一切都非常随机。

有人知道为什么会发生这种情况或如何避免吗?

【问题讨论】:

切勿在 -dealloc-init 中使用属性访问器。永远。 你是说 UISwitch 出现了随机数据,但我看不到你在哪里设置这些数据? cellForRowAtIndexPath 中不应该有一行设置该值吗? @jacob-relkin 您的建议背后的原因是什么?在 init 中允许属性访问器可以减少错误代码 - 因为您的访问器正确管理属性的性质(保留与分配),您不能忘记保留属性,并且您不能通过更改来引入内存问题保留/分配方面,然后忘记修复 init 方法。您是否考虑过子类覆盖 setter 方法并在 super 处于不一致状态时执行操作的风险? 在这里找到更多讨论:***.com/questions/1283419/… @mackworth - 你是对的,我认为开关会是持久的,但现在你提到很明显你必须在 cellForRowAtIndexPath 中设置它。我想我会去试试。 【参考方案1】:

麦克沃斯是对的。我只需要为每个 UISwitch 的状态创建一个包含布尔值的数组,然后在 cellForrowAtIndexPath 中分配它。

【讨论】:

以上是关于自定义 UITableView 的意外行为的主要内容,如果未能解决你的问题,请参考以下文章

在ios的uitableview中自定义单元格编辑样式

自定义 ListView 适配器的意外行为

在 tableviewcell 中使用 UITableview 执行 segue

在两个 UITableView 之间转换时如何模仿 UINavigation 动画行为

添加到自定义 UICollectionViewCell 时出现意外的 CAShapeLayer 行为

使用 LocalDate 字段读取对象时自定义 ObjectInputStream 的意外行为