Я создаю простой контрольный список в UITableView. Я добавил возможности редактирования, разместив обычную кнопку редактирования на панели навигации. Кнопка включает режим редактирования. Режим редактирования отлично работает, пока я не добавлю специальные флажки (как кнопки) в аксессуар каждой ячейки. Я использую этот код, чтобы сделать это:Проблемы с использованием пользовательской кнопки в представлении Access UITableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:@selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
// put the index path in the button's tag
checkBox.tag = [indexPath row];
}
return cell;
}
Как вы можете видеть, я использую тег баттона передать indexPath моему didCheckTask: метод:
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
Флажки и редактирование все, кажется, работают нормально на поверхности. Однако возникает большая проблема, когда я вхожу в режим редактирования, удаляю элемент в таблицеView, а затем пытаюсь использовать этот флажок. Например, если удалить первый элемент в Tableview, а затем попытаться проверить флажок последнего пункта, программа падает с:
2012-05-06 21: 45: 40,645 CheckList [16022: F803] * Нагрузочный приложение из-за для неперехваченного исключения 'NSRangeException', причина: '* - [__ NSArrayM objectAtIndex]: индекс 4 за пределами [0 .. 3]
Я пытался выяснить, источник этой ошибки, но мне не повезло. Я мог бы действительно использовать некоторую помощь - я новичок в какао. Далее следует соответствующий код.
CLTaskFactory.h
#import <Foundation/Foundation.h>
@interface CLTaskFactory : NSObject
{
NSString *taskName;
BOOL didComplete;
}
@property NSString *taskName;
- (void)setDidComplete:(BOOL)dc;
- (BOOL)didComplete;
@end
CLTaskFactory.m
#import "CLTaskFactory.h"
@implementation CLTaskFactory
@synthesize taskName;
- (void)setDidComplete:(BOOL)dc
{
didComplete = dc;
}
- (BOOL)didComplete
{
return didComplete;
}
- (NSString *)description
{
// override the description
NSString *descriptionString = [[NSString alloc] initWithFormat:@"%@", taskName];
return descriptionString;
}
@end
CLTaskStore.h
#import <Foundation/Foundation.h>
@class CLTaskFactory;
@interface CLTaskStore : NSObject
{
NSMutableArray *allTasks;
}
+ (CLTaskStore *)sharedStore;
- (NSMutableArray *)allTasks;
- (void)addTask:(CLTaskFactory *)task;
- (void)removeTask:(CLTaskFactory *)task;
- (void)moveTaskAtIndex:(int)from toIndex:(int)to;
@end
CLTaskStore.m
#import "CLTaskStore.h"
@implementation CLTaskStore
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
+ (CLTaskStore *)sharedStore
{
static CLTaskStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
- (id)init
{
self = [super init];
if (self) {
allTasks = [[NSMutableArray alloc] init];
}
return self;
}
- (NSMutableArray *)allTasks
{
return allTasks;
}
- (void)addTask:(CLTaskFactory *)task
{
[allTasks addObject:task];
}
- (void)removeTask:(CLTaskFactory *)task
{
[allTasks removeObjectIdenticalTo:task];
NSInteger taskCount = [allTasks count];
NSLog(@"Removed: %@, there are now %d remaining tasks, they are:", task, taskCount);
for (int i = 0; i < taskCount; i++) {
NSLog(@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i]);
}
}
- (void)moveTaskAtIndex:(int)from toIndex:(int)to
{
if (from == to) {
return;
}
CLTaskFactory *task = [allTasks objectAtIndex:from];
[allTasks removeObjectAtIndex:from];
[allTasks insertObject:task atIndex:to];
}
@end
CLChecklistViewController.h
#import <Foundation/Foundation.h>
@class CLTaskFactory;
@interface CLCheckListViewController : UIViewController
{
CLTaskFactory *task;
}
- (void)didCheckTask:(UIButton *)button;
@end
CLCheckListViewController.m
#import "CLCheckListViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"
@implementation CLCheckListViewController
{
__weak IBOutlet UITableView *checkList;
}
- (id)init
{
self = [super init];
if (self) {
// add five sample tasks
CLTaskFactory *task1 = [[CLTaskFactory alloc] init];
[task1 setTaskName:@"Task 1"];
[task1 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task1];
CLTaskFactory *task2 = [[CLTaskFactory alloc] init];
[task2 setTaskName:@"Task 2"];
[task2 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task2];
CLTaskFactory *task3 = [[CLTaskFactory alloc] init];
[task3 setTaskName:@"Task 3"];
[task3 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task3];
CLTaskFactory *task4 = [[CLTaskFactory alloc] init];
[task4 setTaskName:@"Task 4"];
[task4 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task4];
CLTaskFactory *task5 = [[CLTaskFactory alloc] init];
[task5 setTaskName:@"Task 5"];
[task5 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task5];
}
return self;
}
- (void)viewDidLoad
{
[[self navigationItem] setTitle:@"Checklist"];
// create edit button
[[self navigationItem] setLeftBarButtonItem:[self editButtonItem]];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[CLTaskStore sharedStore] allTasks] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:@selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
// put the index path in the button's tag
checkBox.tag = [indexPath row];
}
return cell;
}
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
// set editing mode
if (editing) {
self.navigationItem.title = @"Edit Checklist";
[checkList setEditing:YES];
} else {
self.navigationItem.title = @"Checklist";
[checkList setEditing:NO];
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// remove guest from store
if (editingStyle == UITableViewCellEditingStyleDelete) {
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]];
[[CLTaskStore sharedStore] removeTask:task];
// remove guest from table view
[checkList deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[[CLTaskStore sharedStore] moveTaskAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]];
}
@end
Большое вам спасибо за вашу помощь и знания!
отредактирован:
я изменил два метода с зацикливание NSLogs, чтобы получить некоторое представление. Во-первых, CLTaskStore:
- (void)removeTask:(CLTaskFactory *)task
{
[allTasks removeObjectIdenticalTo:task];
NSInteger taskCount = [allTasks count];
NSLog(@"Removed: %@, there are now %d remaining tasks, they are:", task, taskCount);
for (int i = 0; i < taskCount; i++) {
NSLog(@"%@, status: %@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete][email protected]"YES":@"NO");
}
}
Во-вторых, CLTaskListViewController:
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
NSInteger taskCount = [[[CLTaskStore sharedStore] allTasks] count];
for (int i = 0; i < taskCount; i++) {
NSLog(@"%@, status: %@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete][email protected]"YES":@"NO");
}
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
я заметил две вещи. Если я удалю вверх, снизу вверх, проблем нет. Я могу проверить все - все работает. Однако, если я удалю первую строку, а затем проверит последнюю строку, программа выйдет из строя. NSLog от удаления является чистым, его работа прекрасна.
Если я удаляю первую строку и проверяю четвертую строку, проверяется NSLog из отчета CLTaskStore, строка 5.
В этом проблема. После удаления они находятся в определенном порядке.
В методе didCheckTask вы можете поместить NSLog в начале метода, а другой - непосредственно перед [checkList reloadData]. И попробуйте снова создать ошибку. Посмотрите, сможете ли вы видеть, какой журнал показывался перед сбоем приложения? – user523234
Благодарим за помощь. Я попробовал это. Первый печатный журнал, второй журнал (прямо перед reloadData) не печатался. Похоже, индексирование искажено, но я не могу, чтобы жизнь меня видна там, где это происходит. Является ли использование тега кнопки надежным в этом типе ситуации? (то есть в сочетании с редактированием)? – mySilmaril
Похоже, что массив allTasks имеет меньше элементов, чем ваше табличное представление после удаления. Вы должны поместить некоторые NSLogs для проверки после удаления, что ваш массив allTasks содержит правильные элементы и согласован с вашим текущим представлением таблицы. – user523234