editableCellDidEndOnExit 执行得太晚

发布于 2024-11-02 14:27:17 字数 2017 浏览 0 评论 0原文

我设置了一个用于编辑 tableviewcell 的详细控制器。当我完成单元格编辑后,我使用 editableCellDidEndOnExit 将相应的更改排队到我的数据库中。当焦点从一个单元格转移到另一个单元格时,这种方法效果很好。但是,当用户按下导航栏中的“保存”按钮时,焦点将从正在编辑的单元格转移到“保存”按钮。因此,首先执行通过按“保存”按钮调用的操作,然后执行 editableCellDidEndOnExit 操作。

问题是,当按下保存按钮时,我将排队的更改(使用 NSManagedObject:save:)提交到数据库。仅此后,当调用 editableCellDidEndOnExit 并对最后一个单元格的更改进行排队时。它不会被提交(保存)。

我该如何确保最后一次单元格编辑是在保存之前完成的?

我想我可以存储一个指向正在使用 editableCellDidBeginEditing 编辑的单元格的指针,然后在按下保存按钮时引用该值。有人可以提供其他想法吗?

这是一些相关代码:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.navigationItem.title = @"Client Info";
        self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(doneSave)] autorelease];
        self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)] autorelease];
        keyboardShown = NO;
        currentCell = nil;

        dataInterface = [DataInterfaceObject alloc]; // a singleton
        clientMO = [[Client alloc] init ];
    }
    return self;
}


// queue the change
- (void)editableCellDidEndEditing:(EditableCell *)cell {
    [clientMO setValue:cell.textField.text forKey:cell.keyName];  
};


// commit (save) the changes
- (void) doneSave {
    [dataInterface commitChangesAndNotify:@"clientUpdate"];
    [self.navigationController popViewControllerAnimated:YES];
}

-(void) commitChangesAndNotify:(NSString *)notification{
    if([self.managedObjectContext hasChanges])
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:notification object:nil];  // tell everybody that needs to know about this change (so they can update their view data sources)
        [self.managedObjectContext save:nil];
    }     
}

I have a detail controller set up for editing tableviewcells. When I finish editing a cell, I use editableCellDidEndOnExit to queue a corresponding change to my data base. This works fine when the focus goes from one cell to another. However, when the user presses the Save button in my nav bar, focus goes from the cell being edited to the Save button. As a consequence, the action called by pressing the Save button gets executed first and then the editableCellDidEndOnExit action is executed.

The problem with this is that I commit the queued changed (using NSManagedObject:save:) to the database when the save button is pressed. It is only after that when editableCellDidEndOnExit is called and the change to the last cell is queued. It doesn't get committed (saved).

What can I do to assure that the last cell edit is made before the save?

I suppose I can store a pointer to the cell that is being edited using editableCellDidBeginEditing, and then refer to that value when the save button is pressed. Can someone offer other ideas?

Here is some of the relevant code:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.navigationItem.title = @"Client Info";
        self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(doneSave)] autorelease];
        self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)] autorelease];
        keyboardShown = NO;
        currentCell = nil;

        dataInterface = [DataInterfaceObject alloc]; // a singleton
        clientMO = [[Client alloc] init ];
    }
    return self;
}


// queue the change
- (void)editableCellDidEndEditing:(EditableCell *)cell {
    [clientMO setValue:cell.textField.text forKey:cell.keyName];  
};


// commit (save) the changes
- (void) doneSave {
    [dataInterface commitChangesAndNotify:@"clientUpdate"];
    [self.navigationController popViewControllerAnimated:YES];
}

and

-(void) commitChangesAndNotify:(NSString *)notification{
    if([self.managedObjectContext hasChanges])
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:notification object:nil];  // tell everybody that needs to know about this change (so they can update their view data sources)
        [self.managedObjectContext save:nil];
    }     
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红尘作伴 2024-11-09 14:27:17

我尝试了几种方法来解决这个问题,但在每种情况下, editableCellDidEndEditing:cell: 的事件总是会在提交更改后处理。我尝试更改代码的顺序,看看是否可以更快地处理事件。我尝试用两种方法替换方法 doneSave,其中第一个方法 willSaveOnExit 将事件排队以调用第二个方法 didSaveOnExit。这个想法是将提交操作放入 didSaveOnExit 中,并使事件在 editableCellDidEndEditing 之后排队。

不幸的是,我发现调用 editableCellDidEndEditing:cell 的事件在弹出视图控制器并出现前一个视图之前从未生成。因此尝试重新排列事件队列是没有意义的。我失去了耐心试图找出解决方法,因为我想不出一种方法来与详细视图控制器通信先前视图已经出现。 (我可能能弄清楚,但是,当时,我在这个方向上感觉不太有创意。)

毕竟,以上都不是必要的。

这是我最终所做的:

(这与我在问题中建议的非常相似)

我在 tableviewcontroller 中创建了一个名为 currentCell 的 ivar,我在方法 editableCellDidBeginEditing:cell: 指向正在进行编辑的单元格。

currentCell 在 viewDidAppear 中初始化为 nil

我更改了此代码(请参阅我的原始问题),将代码包装在条件中

- (void)editableCellDidEndEditing:(EditableCell *)cell {
    if (currentCell){
        [clientMO setValue:currentCell.textField.text forKey:currentCell.keyName]; // update the value 
    }
}

我将“保存”按钮处理程序方法更改为此

- (void) doneSave {
    [self editableCellDidEndEditing:currentCell];
    currentCell = nil;
    [dataInterface commitChangesAndNotify:@"clientUpdate"];    
    [self.navigationController popViewControllerAnimated:YES];
}

(将前两行添加到我的问题中的版本)

现在,我知道如果按下了保存按钮,那么用户就完成了编辑,所以我想在提交之前最后一次调用 editableCellDidEndEditing:cell: 变化。但由于我的代码正在调用(而不是事件处理程序),我必须提供单元格指针,该指针是我在单元格编辑开始时获得的,并且已放入 currentCell 中。

然后我将 currentCell 设置为 nil,表示不再有当前单元格。现在,请记住我说过,当上一个视图出现时,仍然会有一个事件在排队等候 editableCellDidEndEditing:cell: 。当该方法执行时,currentCell (!=nil) 的条件测试会失败,并且代码会被绕过。

因此,最终,即使对 editableCellDidEndEditing:cell: 的多余调用仍在发生,一切似乎都按正确的顺序运行。

我现在很高兴。

I tried several things to work this out, but in every case, the event for editableCellDidEndEditing:cell: always would be handled after the changes were committed. I tried changing the order of my code to see if I could get the event to be handled sooner. I tried replacing the method doneSave with two methods, where the first method, willSaveOnExit, queues an event to call the second method, didSaveOnExit. The idea was to put the commit operation into didSaveOnExit and have the event queued after the editableCellDidEndEditing.

Unfortunately, I discovered that the event calling editableCellDidEndEditing:cell was never generated until the view controller was popped and the previous view had appeared. So trying to rearrange the event queue was pointless. I lost patience trying to figure out a way around that, because I couldn't think of a way to communicate to the detailed view controller that the previous view had appeared. (I could probably figure it out, but, at the time, I wasn't feeling too creative in that direction.)

None of the above was necessary, after all.

Here is what I ended up doing:

(which is very much like what I suggested in my question)

I created an ivar in the tableviewcontroller called currentCell, which I set in the method editableCellDidBeginEditing:cell: pointing to the cell where editing is being done.

currentCell is initialized to nil in viewDidAppear

I changed this code (see my question for the original), wrapping the code in the conditional

- (void)editableCellDidEndEditing:(EditableCell *)cell {
    if (currentCell){
        [clientMO setValue:currentCell.textField.text forKey:currentCell.keyName]; // update the value 
    }
}

I changed the Save button handler method to this

- (void) doneSave {
    [self editableCellDidEndEditing:currentCell];
    currentCell = nil;
    [dataInterface commitChangesAndNotify:@"clientUpdate"];    
    [self.navigationController popViewControllerAnimated:YES];
}

(adding the first two lines to the version in my question)

Now, I know that if the save button has been pressed, then the user is done editing, so I want to call editableCellDidEndEditing:cell: one last time before I commit the changes. But since my code is calling (rather than the event handler) I have to provide the cell pointer, which I obtained when the cell edit began, and had put in currentCell.

I then set currentCell to nil, indicating that there is no longer a current cell. Now, remember that I said there is still going to be an event queued up for editableCellDidEndEditing:cell: by the time the previous view appears. When that method executes, the conditional test for currentCell (!=nil) drops through, and the code is bypassed.

So in the end, it appears that everything is working in the right order, even though the superfluous call to editableCellDidEndEditing:cell: still is occurring.

I'm happy for now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文