2

我正在开发我的第一个应用程序,需要一些帮助。我已经阅读了大量关于 SO 的类似问题,但没有得到任何结果。

我有一个简单的表格视图控制器,它有一个加号按钮;按下时,会导致模态视图控制器要求用户将信息插入到 4 个单独的字段中。当用户点击保存时,模式视图消失,信息显示在表格视图中,因为保存按钮调用 NSManagedObject 子类并通过核心数据保存它。

我正在尝试使用它,以便当用户输入第一个字段(名称)时,如果他们之前已经输入过该名称(如果他们使用 save 方法将其添加到 Core Data),它会自动填充并显示具有与该名称匹配的条目的隐藏表视图。我第一次开始使用 NSMutableArray,但由于 Jeff 的评论,它不会持久地保留数据,所以因为我已经拥有 Core Data 功能,所以使用它更有意义。我正在编辑这篇文章以包括我的核心数据当前是如何设置的。

我基本上想实现这一点,但使用核心数据(http://www.dalmob.org/2011/03/01/alternative-autocomplete-uitextfield/

有一个与人员实体有关系的信息实体。

- (IBAction)save:(id)sender
{
    NSManagedObjectContext *context = [self managedObjectContext];
    Information *information = [NSEntityDescription insertNewObjectForEntityForName:@"Information" inManagedObjectContext:context];

    People *enteredPerson = (People *)[People personWithName:self.nameTextField.text inManagedObjectContext:context];
    information.whichPerson = enteredPerson;
    NSError *error = nil;
    if (![context save:&error])
    {
        NSLog(@"Can't save! %@ %@", error, [error localizedDescription]);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}

enterPerson 调用 People NSManagedObjectSubclass 中的 personWithName 方法:

+ (People *)personWithName:(NSString *)name inManagedObjectContext:(NSManagedObjectContext *)context
{
    People *people = nil;

    // Creating a fetch request to check whether the name of the person already exists
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"People"];
    request.predicate = [NSPredicate predicateWithFormat:@"name = %@", name];
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
    request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    NSError *error = nil;
    NSArray *fetchedPeople = [context executeFetchRequest:request error:&error];
    if (!fetchedPeople)
    {
        // Handle Error
    }
    else if (![fetchedPeople count])
    {
        // If the person count is 0 then let's create it
        people = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:context];
        people.name = name;
    }
    else
    {
        // If the object exists, just return the last object .
        people = [fetchedPeople lastObject];
    }
    return people; 
}

根据创建 NSFetchRequest 的建议,我想知道执行此操作的最佳技术。

我是否在最后添加条目的 Save 方法中执行此操作,如下所示:

// NSFetchRequest

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

// Specifiy a predicate here if there are certain conditions your fetch must adhere to
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY name CONTAINS[c] %@", self.nameTextField.text];
[fetchRequest setPredicate:predicate];

//NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
    // Handle error
}
if ([fetchedObjects count] == 0)
{
    // Add entry to results
}

我想要实现的是,从核心数据中,当用户输入名称时,引用核心数据(带有获取请求),如果该名称存在,当用户开始输入时,填充位于文本字段下方的表视图.

任何指导将不胜感激。

编辑:我已经用一些进一步的代码更新了一个答案,几乎可以让它工作。

编辑:更多代码:

.h 中的属性声明

@property (retain, nonatomic) IBOutlet UITextField *nameTextField;
@property (nonatomic, retain) NSString *substring;
@property (weak, nonatomic) IBOutlet UITableView *testTableView;
@property (nonatomic, retain) NSFetchedResultsController* autocompleteFetchedResultsController;

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring;

ViewDidLoad

- (void)viewDidLoad
{
    NSError *error;
    if (![[self autocompleteFetchedResultsController] performFetch:&error])
    {
        NSLog(@"Unresolved error %@ %@", error, [error userInfo]);
        exit(-1);
    }
    self.testTableView.delegate = self;
    self.testTableView.dataSource = self;
    self.testTableView.hidden = YES;
    self.testTableView.scrollEnabled = YES;
    self.nameTextField.delegate = self;
    [super viewDidLoad];
}

保存方法

- (IBAction)save:(id)sender
{
    NSManagedObjectContext *context = [self managedObjectContext];
    Transaction *transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];    
    People *enteredPerson = (People *)[People personWithName:self.nameTextField.text inManagedObjectContext:context];
    transaction.whoFrom = enteredPerson;
    NSError *error = nil;
    if (![context save:&error])
    {
        NSLog(@"Can't save! %@ %@", error, [error localizedDescription]);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}

谢谢,

4

3 回答 3

0

使用来自 Xcode 代码片段库的基本代码,您可以执行核心数据获取:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"<#Entity name#>" inManagedObjectContext:<#context#>];
[fetchRequest setEntity:entity];

// Specifiy a predicate here if there are certain conditions your fetch must adhere to
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"<#Predicate string#>", <#Predicate arguments#>];
[fetchRequest setPredicate:predicate];

NSError *error = nil;
NSArray *fetchedObjects = [<#context#> executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
    // Handle error
}

将实体名称替换为存储您的 NameTextField 条目的名称。fetchedObjects 是一个数组,用于存储填充表格所需的信息。

显然,您还需要通过创建新实体并保存上下文来将任何新的 NameTextField 条目保存到核心数据。

于 2013-11-25T10:59:42.867 回答
0

我有点得到这个工作。我没有更新整个问题,而是将其留在那里以供参考,因为我相信有人会遇到类似的情况。通过在我的视图控制器中使用 FetchedResultsController 对象,我现在获得了一个名称列表来填充位于文本字段下方的表视图。

让我们看一些代码:

- (NSFetchedResultsController *)autocompleteFetchedResultsController
{
    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    if (_autocompleteFetchedResultsController != nil)
    {
        return _autocompleteFetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"People" inManagedObjectContext:managedObjectContext];
    fetchRequest.entity = entity;

    if ([self.substring length] > 0) {
        NSPredicate *peoplePredicate = [NSPredicate predicateWithFormat:@"ANY name CONTAINS[c] %@", self.nameTextField.text];

        [fetchRequest setPredicate:personPredicate];
    }

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    self.autocompleteFetchedResultsController = theFetchedResultsController;    _autocompleteFetchedResultsController.delegate = self;
    return _autocompleteFetchedResultsController;
}

- (void)viewDidLoad
{

    NSError *error;
    // I am performing the fetchHere and if there is an error, it will get logged.
    if (![[self autocompleteFetchedResultsController] performFetch:&error])
    {
        NSLog(@"Unresolved error %@ %@", error, [error userInfo]);
        exit(-1);
    }

    // Further code relating to tableview to make it hidden, etc
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    id  sectionInfo = [[_autocompleteFetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    self.testTableView.hidden = NO;
    self.substring = self.nameTextField.text];
    self.substring = [self.substring stringByReplacingCharactersInRange:range withString:self.substring];
    [self searchAutocompleteEntriesWithSubstring:self.substring];
    return YES;
}

#pragma mark UITableViewDataSource methods


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"autocomplete cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    People *people = [self.autocompleteFetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = people.name;
    return cell;
}

#pragma mark UITableViewDelegate methods

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
    self.nameTextField.text = selectedCell.textLabel.text;

}

所以这在某种程度上是有效的。当我将光标放在 nameTextField 中时,它会取消隐藏表格视图,但它当前会显示所有已输入名称的名称。

我想要的是能够在我打字时让表格只显示匹配的内容。

[self searchAutocompleteEntriesWithSubstring:substring];里面是shouldChangeCharactersInRangeMethod调用我创建的自定义方法。

当我将此设置为 NSMutableArray 而不是使用 Core Data 时,它是下面的代码,但我不知道如何调整此代码来搜索核心数据并仅显示与我已经输入的内容匹配的结果。

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {

        self.autocompleteFetchedResultsController = nil;
        [self autocompleteFetchedResultsController];
        [self.testTableView reloadData];
}

我快到了——只需要一点推动力就可以到达那里!

于 2013-11-25T13:25:54.000 回答
0

我猜 self.autocompleteUrls 是你之前的 NSMutableArray ......好吧,你已经走了很长一段路,现在看到 autocompleteFetchedResultsController -> 那是获取的内容,条件 if (_autocompleteFetchedResultsController != nil) 保护属性方法不被调用每次 U 引用 autocompleteFetchedResultsController。所以你应该做这样的事情:

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
    _autocompleteFetchedResultsController = nil;
    [self autocompleteFetchedResultsController];
    [self.testTableView reloadData];
}

如果你正确地完成了其他所有事情,那应该是......

您的 cellForRowAtIndexPath 应该如下所示:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"autocomplete cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    if(cell == nil){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier];
    }

    People *people = [self.autocompleteFetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = people.name;
    return cell;
}
于 2013-11-25T15:13:46.103 回答