2016-08-08 68 views
1

Ich bin mit einem seltsamen Fehler zum Nachladen eines UITableViewCell enthält UITextField mit einem benutzerdefinierten rightView konfrontiert.Reloading Zeile enthält UITextField mit einem RightView verursacht Endlosschleife und Speicherüberlauf

habe ich ein sehr einfaches Beispiel, die Fehler zu demonstrieren:

Meine benutzerdefinierte Zelle mit einem UITextField:

@implementation TableViewCell 

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 
     _textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; 
     _textField.text = @"This is a text field"; 
     [self.contentView addSubview:_textField]; 
    } 

    return self; 
} 

@end 

My-View-Controller mit einem UITableView:

@interface ViewController() <UITableViewDataSource> 

@property (weak, nonatomic) IBOutlet UITableView *tableView; 
@property (nonatomic) UIView *rightView; 

@end 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    // Press to reload the row with rightView 
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(reloadRow)]; 

    // Create rightView and store to a property 
    _rightView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; 
    _rightView.backgroundColor = [UIColor greenColor]; 

    [_tableView registerClass:[TableViewCell class] forCellReuseIdentifier:@"Cell"]; 
    _tableView.dataSource = self; 
} 

- (void)reloadRow { 
    [_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 
                  inSection:0]] 
         withRowAnimation:(UITableViewRowAnimationAutomatic)]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return 1; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 

    cell.textField.rightView = _rightView; 
    cell.textField.rightViewMode = UITextFieldViewModeAlways; 

    return cell; 
} 

@end 

App screenshot

Das ist es. Dann drücke ich den Reload-Button. Die Endlosschleife wird gestartet, die Anwendung hängt. Nach einigen Sekunden stürzt die App, weil es zu viel Speicher verwendet:

Terminated due to memory error.

Aber, wenn ich die rightView in einer Eigenschaft nicht speichern und neue Ansicht erstellen jedes Mal tableView dequeue der Zelle, dann gibt wird kein Problem sein.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 

    cell.textField.rightView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; 
    cell.textField.rightView.backgroundColor = [UIColor greenColor]; 
    cell.textField.rightViewMode = UITextFieldViewModeAlways; 

    return cell; 
} 

Aber mein rightView (real app) ist keine einfache Ansicht so will ich nicht, neu zu erstellen, es jedes Mal die Zeile auftaucht.

Wer weiß, warum das passiert ist? Warum ist es nicht passiert, wenn ich die rightView nicht aufbewahre? Danke fürs Lesen.

+0

zurückkehren wird, warum Sie nicht die richtige Ansicht in Ihrem TableViewCell wie das Textfeld erstellen? – thorb65

+0

Ich habe eine Unterklasse von 'UITableViewCell', die an jeder Stelle in der App zu verwenden ist, und ich verwende' rightView' nur in einem View-Controller, so dass ich es nicht innerhalb der Zellen-Unterklasse hinzufügen möchte. – kientux

+0

Der richtige Weg ist, verschiedene UITableViewCell-Klassen zu verwenden, nicht nur eine über die ganze App :-) – thorb65

Antwort

0

Sie versuchen, eine Ansicht zu mehreren superview hinzuzufügen. Das kannst du nicht tun. Ihre @property (nonatomic) UIView *rightView kann nur eine superView haben. Versuchen Sie löschen es aus Subviews cell.textField.subviews

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 
    for (UIView *subview in cell.textField.subviews) { 
     if ([subview isEqual:_rightView]) { 
      [subview removeFromSuperView]; 
     } 
    } 
    cell.textField.rightView = _rightView; 
    cell.textField.rightViewMode = UITextFieldViewModeAlways; 

    return cell; 
} 

Oder ein Gewebe Methode machen, die Instanz von rightView

+0

Ich habe versucht, was Sie sagen, aber das Problem ist immer noch da. Und ja, ich habe eine Methode erstellt, um jedes Mal, wenn die Zelle es benötigt, ein neues 'rightView' zu erstellen, das das Problem löst, aber wie gesagt, meine benutzerdefinierte Ansicht ist keine einfache Ansicht, deshalb möchte ich sie nicht viele Male neu erstellen würde die tableView während des Scrollens flackern lassen. – kientux

+0

Ich bin ein bisschen meine Antwort geändert, versuchen Diff Weg löschen von Subviews – iSashok