1

我完成了以下从 csv 文件中获取数据并将其发布到表格视图中的任务。我想做的是使用 uisegmented 控件对我拥有的核心数据进行排序和过滤。

我有一个有点像这样的名字列表,我把它作为名字、姓氏和性别存储在数据模型中。我设计了以下屏幕截图。通过单击 az 按钮或 za 按钮。数据应根据性别(如男性、女性或两者兼而有之)进行排序和过滤。

在此处输入图像描述

我是核心数据(排序和过滤)和 UISegmented 控件的新手。您能否帮助我详细完成上述任务以及您是如何完成的。

以下是我到目前为止所做的工作的代码。我正在使用xib。

RootViewController.h

#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

@interface RootViewController : UITableViewController

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

@property (retain) NSArray *people;

//! Filtering view from XIB file
@property (nonatomic, retain) IBOutlet UIView *filterSortView;

//! Filter control
@property (nonatomic, retain) IBOutlet UISegmentedControl *filterControl;

//! Sort control
@property (nonatomic, retain) IBOutlet UISegmentedControl *sortControl;

@end

然后我们RootViewController.m

#import "RootViewController.h"
#import "Person.h"

@implementation RootViewController

@synthesize people;
@synthesize managedObjectContext=__managedObjectContext;

// Sorting & filtering UI components
@synthesize filterSortView, filterControl, sortControl;

#pragma mark -
#pragma mark View Lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.navigationItem.title = @"People";

    // Get our people array - this next block of code could probably be extracted out to a private
    // method and generalized for different fetch request types
    NSEntityDescription *personEntity = [NSEntityDescription entityForName:@"Person"
                                              inManagedObjectContext:self.managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:personEntity];
    NSError *error = nil;
    self.people = [self.managedObjectContext executeFetchRequest:request error:&error];
    if (error)
    {
        [NSException raise:NSInternalInconsistencyException format:@"Could not fetch Core Data records: %@",error];
    }
    [request release];

    // Now do a secondary load from another XIB file (other than the main table view)
    [[NSBundle mainBundle] loadNibNamed:@"FilterSortView" owner:self options:nil];

    // This disables the default selection
    self.filterControl.selectedSegmentIndex = -1;
    self.sortControl.selectedSegmentIndex = -1;

    // Now register for events when the value changes
    // TODO: write method implementations for each of these and then uncomment these lines.
    //  [self.filterControl addTarget:self action:@selector( -- TODO -- ) forControlEvents:UIControlEventValueChanged];
    //  [self.sortControl addTarget:self action:@selector( -- TODO -- ) forControlEvents:UIControlEventValueChanged];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.filterControl = nil;
    self.sortControl = nil;
    self.filterSortView = nil;
}

#pragma mark -
#pragma mark UITableViewDataSource

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.people count];
}

#pragma mark -
#pragma mark UITableViewDelegate

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

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

    Person *person = [self.people objectAtIndex:[indexPath row]];
    cell.textLabel.text = [NSString stringWithFormat:@"%@, %@",person.lastName,person.firstName];
    return cell;
}


 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return self.filterSortView;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return self.filterSortView.frame.size.height;
}

#pragma mark -
#pragma mark Class Plumbing

- (void)dealloc
{
    [filterControl release];
    [sortControl release];
    [filterSortView release];

    [people release];

    [__managedObjectContext release];
    [super dealloc];
}

@end

然后我们有 FilteredListAppDelegate.h

#import <UIKit/UIKit.h>

@interface FilteredListAppDelegate : NSObject <UIApplicationDelegate> {

}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

@end

然后我们有 FilteredListAppDelegate.m

#import "FilteredListAppDelegate.h"

#import "RootViewController.h"

#import "Person.h"

// Private methods
@interface FilteredListAppDelegate ()
- (BOOL) _populateCoreData;
@end



@implementation FilteredListAppDelegate


@synthesize window=_window;
@synthesize managedObjectContext=__managedObjectContext;
@synthesize managedObjectModel=__managedObjectModel;
@synthesize persistentStoreCoordinator=__persistentStoreCoordinator;
@synthesize navigationController=_navigationController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Prepopulate Core Data with our data, if necessary.
    NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
    if ([settings objectForKey:@"core_data_populated"] == nil)
    {
        BOOL success = [self _populateCoreData];
        if (success)
        {
            [settings setValue:[NSNumber numberWithBool:YES] forKey:@"core_data_populated"];
        }
    }

    // Override point for customization after application launch.
    // Add the navigation controller's view to the window and display.
    self.window.rootViewController = self.navigationController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
  /*
   Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
   Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
   */
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
  /*
   Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
   If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
   */
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
  /*
   Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
   */
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
  /*
   Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
   */
}

- (void)applicationWillTerminate:(UIApplication *)application
{
  // Saves changes in the application's managed object context before the application terminates.
    [self saveContext];
}

- (void)dealloc
{
    [_window release];
    [__managedObjectContext release];
    [__managedObjectModel release];
    [__persistentStoreCoordinator release];
    [_navigationController release];
    [super dealloc];
}

- (void)awakeFromNib
{
    RootViewController *rootViewController = (RootViewController *)[self.navigationController topViewController];
    rootViewController.managedObjectContext = self.managedObjectContext;
}

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
        {
            /*
             Replace this implementation with code to handle the error appropriately.

             abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

#pragma mark - Private Methods

/**
 * Hacky method to just throw a bunch of data into Core Data.
 */
- (BOOL) _populateCoreData
{
    NSManagedObjectContext *context = [self managedObjectContext];

    // Get the names out of the text file
    NSError *error = nil;
    NSString *filename = [[NSBundle mainBundle] pathForResource:@"actors_by_gender" ofType:@"csv"];
    NSString *fileContents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&error];
    if (error)
    {
        [NSException raise:NSInternalInconsistencyException format:@"Unable to read text file for adding to Core Data"];
    }

    NSArray *namesChoppedByNewline = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
    for (NSString *singleNameRecord in namesChoppedByNewline)
    {
        NSArray *attributesChoppedByComma = [singleNameRecord componentsSeparatedByString:@","];

        // Now make each record a new Core Data object
        Person *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
        newPerson.firstName = [attributesChoppedByComma objectAtIndex:0];
        newPerson.lastName  = [attributesChoppedByComma objectAtIndex:1];
        newPerson.gender    = [attributesChoppedByComma objectAtIndex:2];
    }

    if (![context save:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        [NSException raise:NSInternalInconsistencyException
                format:@"Couldn't save Core Data data for Person entity import. Reason: %@",error];
    }
    return YES;
}

#pragma mark - Core Data stack

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
 */
- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil)
    {
        return __managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}

/**
 Returns the managed object model for the application.
 If the model doesn't already exist, it is created from the application's model.
 */
- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil)
    {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FilteredList" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
    return __managedObjectModel;
}

/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"FilteredList.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
    {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.

         Typical reasons for an error here include:
         * The persistent store is not accessible;
         * The schema for the persistent store is incompatible with current managed object model.
         Check the error message to determine what the actual problem was.


         If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

         If you encounter schema incompatibility errors during development, you can reduce their frequency by:
         * Simply deleting the existing store:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

         * Performing automatic lightweight migration by passing the following dictionary as the options parameter: 
         [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

         Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}

#pragma mark - Application's Documents directory

/**
 Returns the URL to the application's Documents directory.
 */
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

@end

感谢您的帮助。

4

2 回答 2

0

NSSortDescriptor在执行之前,您需要在 fetch 请求上创建并设置一个实例。

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"firstName" ascending:YES];

ascending通过根据您的状态切换参数UISegmentedControl,您可以轻松地以 az 或 za 顺序返回结果。

或者,您可以将相同的排序描述符应用于您的人员数组,sortedArrayUsingDescriptors如下所示:

NSArray *array = [[self people] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

但是请记住,当您切换分段控件时,您将需要再次执行获取请求,或者将您的数组排序到一个新数组中(也许可以使用NSMutableArray)。

要实现分段控件,您需要添加目标和选择器:

[[self segmentedControl] addTarget:self action:@selector(segmentedControlEventHandler:) forControlEvents:UIControlEventValueChanged];

然后使用以下方法来修改和更新您的排序描述符和表视图。

- (void)segmentedControlEventHandler:(id)sender
{
    UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;

    if([segmentedControl selectedSegmentIndex] == 0)
    {
        //segment 1 selected
        //set BOOL value for ascending sort descriptor
        //update table view -> [[self tableView] reloadData];
    }
    else
    {
        //segment 2 selected
    }
}
于 2013-10-14T08:06:16.513 回答
0

按性别过滤: NSPredicate *predicatem =[NSPredicate predicateWithFormat:@"gender == %@", @"m" ]; //将谓词赋予fecth请求 request.predicate=predicatem;

于 2013-10-15T04:26:14.807 回答