Search code examples
iosobjective-ccore-datauipickerview

assign fetched data from core data to UIPickerView


I've searched through all stack overflow but no answer really helped me with my problem, although it seems to be an easy one.

I have an app with an entity in which I store strings. I can store them and fetch them in a UITableView very well, but at some point I need to fetch them and put them in a UIPickerView. Here is my class in which is the UIPickerView. As it is in a modal view, there is a delegate to bring back the data in the parent view, but this works fine. The header file:

#import <UIKit/UIKit.h>


@protocol TextChoiceDelegate <NSObject>
- (void) takeBackViewController:(id)controller didFinishSelectingText:(NSString *)text;
@end

@interface ChooseTextViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource> {
    UIPickerView *pickerView;
    NSMutableArray *list;
}

@property (nonatomic, assign) id <TextChoiceDelegate> delegate;
@property (strong, nonatomic) IBOutlet UIPickerView *pickerView;
@property (strong, nonatomic) NSString *text;

- (IBAction)didFinishChoosingText:(id)sender;

@end

And the .m file:

#import "ChooseTextViewController.h"

@interface ChooseTextViewController ()
@property (strong) NSMutableArray *list;
@end


@implementation ChooseTextViewController

@synthesize delegate;

@synthesize pickerView;
@synthesize list;
@synthesize text;


#pragma mark - IBActions

- (IBAction)didFinishChoosingText:(id)sender
{
    NSString *textToPassBack = text;
    NSLog(@"returning: %@", textToPassBack);
    [self.delegate takeBackViewController:self didFinishSelectingText:textToPassBack];

    [self dismissViewControllerAnimated:YES completion:NULL];
}

#pragma mark - UIPickerViewDataSource methods

// Number of components in the pickerView
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

// Number of elements in the pickerView component
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{
    return [self.list count];
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [self.list objectAtIndex:row];
}


#pragma mark - PickeView delegate methods

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    NSLog(@"Selection of element: %@", [self.list objectAtIndex:row]);
    text = [self.list objectAtIndex:row];
}


#pragma mark - View Controller LifeCycle

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view.
    /*
    list = [[NSMutableArray alloc] init];
    [list addObject:@"1"];
    [list addObject:@"2"];
    [list addObject:@"3"];
    [list addObject:@"4"];
    [list addObject:@"5"];
     */
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.list = [[NSMutableArray alloc] init];

    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"LolText"];

    self.list = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
}


#pragma mark - Core Data Stack Methods

- (NSManagedObjectContext *)managedObjectContext
{
    NSManagedObjectContext *context = nil;
    id localDelegate = [[UIApplication sharedApplication] delegate];
    if ([localDelegate performSelector:@selector(managedObjectContext)]) {
        context = [localDelegate managedObjectContext];
    }
    return context;
}

@end

When I run this, the pickerView appears empty and as soon as I click on it the app crashes with this error logs: 2013-07-23 10:51:55.010 MemeGen[51428:c07] * Assertion failure in -[UITableViewRowData rectForRow:inSection:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableViewRowData.m:1630 2013-07-23 10:51:55.012 MemeGen[51428:c07] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path ( 2 indexes [0, 0])' ** First throw call stack: (0x22bb012 0x16e5e7e 0x22bae78 0xe6b665 0x502f20 0x3c62de 0x756086 0x755f7a 0x37940d 0x37b9eb 0x5e485a 0x5e399b 0x5e50df 0x5e7d2d 0x5e7cac 0x5dfa28 0x34c972 0x34ce53 0x32ad4a 0x31c698 0x264fdf9 0x264fad0 0x2230bf5 0x2230962 0x2261bb6 0x2260f44 0x2260e1b 0x264e7e3 0x264e668 0x319ffc 0x27ad 0x26d5) libc++abi.dylib: terminate called throwing an exception

For testing purpose, when I run the commented part of the viewDidLoad method (commenting all about cora data), it works fine. If I put the code from viewDidAppear in viewDidLoad, in crashes as soon as the viewController appears on screen

I fell like I'm not far from the truth but I can't find my way out. Could anybody help me there, please ?


Solution

  • Well, in the end I changed the majority of my code and it works to a certain point. The big problem now is that when I want to use the value returned by the UIPickerView as a String it's impossible, I'm stuck with a value of type: NSKnownKeysDictionary1.

    Here the problematic part, but I can't find a way to obtain a simple String.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        // Core Data
        if (_managedObjectContext == nil)
        {
            _managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
        }
    
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"LolText"];
    
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"LolText" inManagedObjectContext:_managedObjectContext];
        request.resultType = NSDictionaryResultType;
        request.propertiesToFetch = [NSArray arrayWithObject:[[entity propertiesByName] objectForKey:@"text"]];
        request.returnsDistinctResults = YES;
    
    
        _list = [[_managedObjectContext executeFetchRequest:request error:nil] mutableCopy];
    
        for (id key in _list) {
            NSLog(@"class of %@ = %@", key, [key class]);
            NSLog(@"string: %@", (NSString *)[[_list objectAtIndex:1] allValues]);
        }
    
        NSLog (@"texts: %@",_list);
    }
    

    And here are the logs:

    2013-07-23 22:23:16.178 MemeGen[79886:c07] class of {
        text = "MY TEST LOLTEXT";
    } = NSKnownKeysDictionary1
    2013-07-23 22:23:16.178 MemeGen[79886:c07] string: (
        "MY TEST LOLTEXT!"
    )
    

    The fact that I cats it to NSString doesn't solve the problem. I always end on the same "unrecognized selector error", each time I use a NSString method, like for example:

    2013-07-23 22:38:06.497 MemeGen[80800:c07] -[NSKnownKeysDictionary1 stringByReplacingCharactersInRange:withString:]: unrecognized selector sent to instance 0x94e0a60 2013-07-23 22:38:06.498 MemeGen[80800:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSKnownKeysDictionary1 stringByReplacingCharactersInRange:withString:]: unrecognized selector sent to instance 0x94e0a60'

    Is there a way not to get an NSKnownKeysDictionary1 when fetching datas from core data?