I am trying to have a UIPickerController display some users. It works easily enough if I hard code some sample users as follows:
//in viewDidLoad
_users = @[@"Ronald", @"David",
@"Sharon", @"Amir", @"Atul"]; //etc.
However, I want to draw these users from core data. So far I have tried a simple fetch and also nsfetchedresults controller and nothing seems to work. What is the preferred way of getting an array from core data.
//fetchrequest
- (id) getUsers{
NSFetchRequest *fetchRequest = [NSFetchRequest
fetchRequestWithEntityName:@"User"];
fetchRequest.resultType = NSDictionaryResultType;
NSError *error = nil;
self.managedObjectContext = [chModel sharedInstance].managedObjectContext;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest
error:&error];
return results;
}
//this throws an error at
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
NSLog(@"in titleforrow");
return _users[row];//error here. also error if I substitute [0]
}
//when I try
_users = [self.fetchedResultsController fetchedObjects];
}
frc is never called
Two suggestions buddy :)
2.Change your getter for doers to return an array rather than id :). Does not make any sense to return an Array and declare return type as id and then final re-casting it to array to access its entities using subscript syntax :)
Issue in your code
_doers is a instance variable :) self.doers is a property :)
When you synchronize your property using @synchronize (now you don't write it anymore as xcode writes one for you by default ) instance variables which have same name as property but an underscore prefixed to it are used to provide the default setter and getter to your property :)
When you call _doers you are accessing the instance variable and not property, so your getter will never be called :)
How to solve it ??
instead of calling return _doers[row];
call self.doers[row]
Will it solve the issue??
Nope :). It returns an array of user entity objects :) not the array of string :) So if you simply say self.doers[row]
you will return an object of User (Dictionary in your case ) to a method which accepts a string :)
What is the correct way then ??
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
User *userInstance = (User *)self.doers[row];
return userInstance.name; //user entiy attribute which holds name or something like that
}
OR
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return [self.doers[row] valueForKey:@"name"] //user entiy attribute which holds name or something like that
}
it will work :) though very poor model of using getter for a property :)
Is this approach correct ??
Will it work ?? Of course! ... is this correct way to do it ?? No way! :)
For every row in your picker this method gets called because you are accessing property self.doers its getter called for each cell :) which means you will query so many times your core data :)
I think its un-necessary :) What you can do rather is to user NSFetchedResultsController
a singletone variable perform fetch once in viewdidload or viewwillappear as per your requirement and use its feched objects array for your picker :)
else
move the code in getter of doers to a method call it once and populate your property once and once filled use the property to fill the picker :)
Coredata operations are costly :)
Anyway happy coding, all the best :)
Declaimer: Code provided above is only for explaining concepts and not for the purpose of copy paste :) check syntax before using it blindly :)