可编辑的UITableView,单元格中的UITextField,在点击完成时存储数据

5
我已经在这个问题上纠结了一两天,但还是无法按照自己的意愿使其正常工作。我试图模仿通讯录的联系人编辑页面(我知道之前也有人问过这个问题)。
我有一个自定义的UITableViewCell,其中包含一个UITextField,它位于详细文本标签的同一位置,当按下编辑按钮时,它们会隐藏和显示以显示正确的项目。
我使用UITextFieldDelegate将输入到文本字段中的信息存储到字典中,以便在用户单击“完成”时将它们保存到视图数组和我的核心数据模型中。
现在的问题是: 如果在字段中输入文本,没有选择其他字段/单元格,并按下完成,则更改的信息将被忽略,它永远不会存储在字典中。
我的代码目前只在按下完成时将字典的内容打印到NSLog中,因为在字典的状态正确之前,我认为更新单元格毫无意义。
我列出了所有的UITextFieldDelegate方法,并打印了每个东西运行的日志,以尝试跟踪事物的流动方式,但这并没有帮助我理解这个具体问题。
以下是代码:
EditableCellStyle2.h
@interface EditableCellStyle2 : UITableViewCell {
    CGRect editRect;
    UITextField *editField;
}

@property (nonatomic, readonly, retain) UITextField *editField;

@end

EditibleCellStyle2.m

#import "EditableCellStyle2.h"

@implementation EditableCellStyle2

@synthesize editField;

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

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code.
        editRect = CGRectMake(83, 12, self.contentView.bounds.size.width-83, 19);

        editField = [[UITextField alloc] initWithFrame:editRect];
        editField.font = [UIFont boldSystemFontOfSize:15];
        editField.textAlignment = UITextAlignmentLeft;
        editField.textColor = [UIColor blackColor];
        editField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;

        [self.contentView addSubview:editField];

        self.editField.enabled = NO;
        self.editField.hidden = YES;
    }
    return self;
}

-(void)layoutSubviews
{
    [super layoutSubviews]; // layouts the cell as UITableViewCellStyleValue2 would normally look like

    editRect = CGRectMake(self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.origin.y, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.size.height);
    editField.frame = editRect;
}

- (void)willTransitionToState:(UITableViewCellStateMask)state {
    [super willTransitionToState:state];

    if (state & UITableViewCellStateEditingMask) {
        self.detailTextLabel.hidden = YES;
        self.editField.enabled = YES;
        self.editField.hidden = NO;
    }
}

- (void)didTransitionToState:(UITableViewCellStateMask)state {
    [super didTransitionToState:state];

    if (!(state & UITableViewCellStateEditingMask)) {
        self.editField.enabled = NO;
        self.editField.hidden = YES;
        self.detailTextLabel.hidden = NO;
        self.editField.text = self.detailTextLabel.text;
    }
}

- (void)dealloc {
    [editField release];

    [super dealloc];
}

@end

DetailViewController.h

#import <UIKit/UIKit.h>
#import "Entry.h"
#import "Station.h"
#import "EditableCellStyle2.h"

@interface EntryDetailViewController : UITableViewController <UITextFieldDelegate> {
    NSManagedObjectContext *currentContext;
    Entry *passedEntry;

    NSMutableArray *sectionsArray;
    NSMutableDictionary *editModeDict;
}

@property (nonatomic, retain) NSManagedObjectContext *currentContext;
@property (nonatomic, retain) Entry *passedEntry;

-(void)editPressed;
-(void)donePressed;
-(void)cancelPressed;

@end

DetailViewController.m

-(void)editPressed
{
    [self setEditing:YES animated:YES];
}

-(void)donePressed
{
    [self setEditing:NO animated:YES];

    NSLog(@"%@", editModeDict);

    [self.tableView reloadData];
}

-(void)cancelPressed
{
    [self setEditing:NO animated:YES];
    [editModeDict removeAllObjects];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    return [sectionsArray count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    NSArray *thisSection = [sectionsArray objectAtIndex:section];
    return [thisSection count];
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    EditableCellStyle2 *cell = (EditableCellStyle2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[EditableCellStyle2 alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...

    NSArray *array = [sectionsArray objectAtIndex:indexPath.section];
    NSDictionary *dictionary = [array objectAtIndex:indexPath.row];

    id key = [[dictionary allKeys] objectAtIndex:0];

    cell.textLabel.text = [NSString stringWithFormat:@"%@", key];
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", [dictionary objectForKey:key]];

    // Set the edit field to match the detail label on creation so it doesn't look odd on first edit (slide down)
    cell.editField.text = cell.detailTextLabel.text;

    // Set the edit placeholder to match the key
    cell.editField.placeholder = [NSString stringWithFormat:@"%@", key];

    // Set the tag for the edit field for the cell based on what cell is being created
    // We will use this in the UITextField delegate to store the data in a dictionary
    if ([cell.textLabel.text isEqualToString:@"Odometer"])
        cell.editField.tag = kOdometer;
    else if ([cell.textLabel.text isEqualToString:@"Quantity"])
        cell.editField.tag = kQuantity;
    else if ([cell.textLabel.text isEqualToString:@"PricePer"])
        cell.editField.tag = kPricePer;
    else if ([cell.textLabel.text isEqualToString:@"PriceTotal"])
        cell.editField.tag = kPriceTotal;
    else if ([cell.textLabel.text isEqualToString:@"Name"])
        cell.editField.tag = kStationName;
    else if ([cell.textLabel.text isEqualToString:@"Address"])
        cell.editField.tag = kStationAddress;
    else if ([cell.textLabel.text isEqualToString:@"City"])
        cell.editField.tag = kStationCity;
    else if ([cell.textLabel.text isEqualToString:@"State"])
        cell.editField.tag = kStationState;
    else if ([cell.textLabel.text isEqualToString:@"Zip"])
        cell.editField.tag = kStationZip;
    else if ([cell.textLabel.text isEqualToString:@"Notes"])
        cell.editField.tag = kNotes;

    // Set the delegate of the edit field to self
    [cell.editField setDelegate:self];

    return cell;
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    [super setEditing:editing animated:animated];

    // When we go into editing mode, hide the back button, when we come out of editing mode, show it.
    self.navigationItem.hidesBackButton = editing;

    // Replace the back button with a cancel button that is only active while in edit mode
    if (editing) {
        UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelPressed)];
        self.navigationItem.leftBarButtonItem = cancelButton;
        [cancelButton release];

        // clear the right bar button (edit)
        self.navigationItem.rightBarButtonItem = nil;

        // make the right bar button a done button
        UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed)];
        self.navigationItem.rightBarButtonItem = doneButton;
        [doneButton release];
    }
    else {
        // clear out our cancel button
        self.navigationItem.leftBarButtonItem = nil;

        // clear out the right bar button (done)
        self.navigationItem.rightBarButtonItem = nil;

        // make the right bar button an edit button
        UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editPressed)];
        self.navigationItem.rightBarButtonItem = editButton;
        [editButton release];
    }
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleNone;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    switch (textField.tag) {
        case kOdometer:
            [editModeDict setValue:textField.text forKey:@"Odometer"];
            break;
        case kQuantity:
            [editModeDict setValue:textField.text forKey:@"Quantity"];
            break;
        case kPricePer:
            [editModeDict setValue:textField.text forKey:@"PricePer"];
            break;
        case kPriceTotal:
            [editModeDict setValue:textField.text forKey:@"PriceTotal"];
            break;
        case kStationName:
            [editModeDict setValue:textField.text forKey:@"Name"];
            break;
        case kStationAddress:
            [editModeDict setValue:textField.text forKey:@"Address"];
            break;
        case kStationCity:
            [editModeDict setValue:textField.text forKey:@"City"];
            break;
        case kStationState:
            [editModeDict setValue:textField.text forKey:@"State"];
            break;
        case kStationZip:
            [editModeDict setValue:textField.text forKey:@"Zip"];
            break;
        case kNotes:
            [editModeDict setValue:textField.text forKey:@"Notes"];
            break;
        default:
            break;
    }

    return YES;
}   

- (BOOL)textFieldShouldReturn:(UITextField *)textField {    
    [textField resignFirstResponder];
    return YES; 
}


- (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;

    sectionsArray = nil;
}

- (void)dealloc {
    [sectionsArray release];
    [editModeDict release];

    [currentContext release];
    [passedEntry release];

    [super dealloc];
}

@end

你在哪里分配/初始化editModeDict?你确定[editModeDict setValue:forKey:]被调用了吗?NSLog()的输出是什么? - Felix
哈,忘记了那部分。在viewDidLoad中,editModeDict被分配和初始化。这绝对是有效的。 - Chuck
看起来我已经解决了这个问题,通过在我的donePressed方法的开头放置[self.view.window endEditing: YES];,这使得所有编辑但仍然是第一响应者的文本字段通过它们的结束编辑方法,更新字典。 - Chuck
如何直接打印NSDictionary内容。您需要循环遍历所有键并打印相应的值。 - Vijay Shankar
你可以将一个字典对象打印到NSLog中进行测试。NSLog(@"%@", aDictionary) 可以正常工作。 - Chuck
3个回答

0
尝试这个:
创建一个方法。
  -(NSString *)getInEditTextFieldValue
  {
      if([myTextField isFirstResponder])
     {
           // get the text of myTextField and set it to text.
           return myTextField.text;
     }
     else
     {
           return nil;
     }
  }

而在你的donePressed方法中:

  -(void)donePressed
  {
        NSString* myText = [self getInEditTextFieldValue];

        if(myText != nil)
        {
              // add myText to your dictionary
        }

        // save logic goes here...

        // reload data for table view...
  }

我现在没有我的Mac,所以无法尝试代码,但逻辑对我来说绝对有效。您的UITextFieldDelegate方法应该获取除第一个响应者之外的所有文本字段的值。您需要做的是多做一些工作来检查和获取该值。

希望这可以帮助到您。


0

你的doneButton()在textFieldShouldEndEditing之前被调用。尝试更改响应者,你会发现在doneButton点击时处于活动状态的那个响应者不会保存其数据。


0
你需要先正确引用你的textfield在UITableCell中。然后在点击完成按钮方法时,你也可以获取单元格对象。根据你的类型对象(在你的情况下是UITextField类型)的contentView可以被获取,你可以从中获取文本。这样你就可以更新所有字段的数据库了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接