UISegmentedcontrol用于排序和过滤核心数据

时间:2013-10-14 07:07:08

标签: iphone core-data uisegmentedcontrol

我完成了以下任务:从csv文件中获取数据并在表视图中发布它。我想做的是使用uisegmentented控件来排序和过滤我拥有的核心数据。

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

enter image description here

我是核心数据(排序和过滤)和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

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

您需要在执行获取请求之前创建并设置NSSortDescriptor的实例。

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

根据您的ascending状态切换UISegmentedControl参数,您可以轻松地以a-z或z-a顺序返回结果。

或者,您可以使用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
    }
}

答案 1 :(得分:0)

按性别过滤:NSPredicate * predicatem = [NSPredicate predicateWithFormat:@“gender ==%@”,@“m”];         //为fecth请求提供谓词         request.predicate = predicatem;

相关问题