Here, m try to sort the array when refersh the tableview but is crash the application when refresh tableview.
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[_PFArray
sortUsingDescriptors:]: unrecognized selector sent to instance
0x6080000550c0'
#interface TableViewController () {
NSMutableArray *returnArray;
}
#end
- (void)viewDidAppear:(BOOL)animated {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate manageObjectContext];
NSError *error = nil;
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Resgistration" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:#"Unique",nil]];
returnArray = [[NSMutableArray alloc] init];
returnArray = [context executeFetchRequest:request error:&error];
for(Resgistration* reg in returnArray) {
NSLog(#"%#", reg);
NSLog(#"%#", reg.roshan);
}
[self.tableView reloadData];
UIColor *gray = [UIColor colorWithRed:234/255.0 green:234/255.0 blue:234/255.0 alpha:1.0];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:#"Please Wait"];
[refreshControl setBackgroundColor:gray];
[refreshControl addTarget:self action:#selector(sortArray) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
}
- (void)sortArray
{
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedStandardCompare:)];
NSMutableArray *sortDescriptior = [[NSMutableArray alloc] initWithObjects:sort, nil];
[returnArray sortUsingDescriptors:sortDescriptior]; // crash the app
[self.tableView reloadData];
[self.refreshControl endRefreshing];
}
Please help me to fix this problem. Thank you.
_PFArray is a subclass of NSArray and is immutable. You can use sortUsingDescriptors: on mutable array only, hence the crash.
It looks like somewhere along the code you have assigned instance of CoreData array inside returnArray variable. There you must use mutableCopy method to convert the immutable array to its mutable version, something like this:
returnArray = [<data array fetched from core data> mutableCopy];
Edit after looking at complete code
returnArray = [[context executeFetchRequest:request error:&error] mutableCopy];
Related
Hi I am developing IOS application in which I am using core data. In my application I am using split view controller. So my split view controller's master view contains following things:
-(void) viewWillAppear:(BOOL)animated
{
[self getNotificationCounter];
[self getTicketCounter];
}
-(void) getNotificationCounter:(UITableViewCell *) cell
{
dispatch_queue_t myQueue = dispatch_queue_create("My Notification Queue",NULL);
dispatch_async(myQueue, ^{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"NotificationsData" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; dispatch_async(dispatch_get_main_queue(), ^{
//update view;
});
});
}
-(void) getTicketCounter:(UITableViewCell *) cell
{
dispatch_queue_t myQueue = dispatch_queue_create("My Ticket Queue",NULL);
dispatch_async(myQueue, ^{
NSFetchRequest *ticketFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ticketEntity = [NSEntityDescription
entityForName:#"Tickets" inManagedObjectContext:context];
[ticketFetchRequest setEntity:ticketEntity];
NSError *ticketError = nil;
NSArray *ticketFetchedObjects = [context executeFetchRequest:ticketFetchRequest error:&ticketError];
dispatch_async(dispatch_get_main_queue(), ^{
// update view
});
});
}
and detail view controller have following thing.
- (NSFetchedResultsController *)fetchedResultsController {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#“channels” inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"channelId" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
So my problem is like this :
In my detail view controller I have one NSFetchRequestController and in master view have two
two NSFetchRequest with two GCD. if I start my application in portrait mode its works fine. But in landscape mode it stops without giving any error. Another thing If remove one GCD NSFetchRequest from master controller it works fine Or if I remove NSFetechResultController then also it works fine. Why it is so? Am I doing some thing wrong. Need Some help. Thank you.
You may not let NSManagedObjectContext or NSManagedObject cross threads.
You must create a fresh context for your thread.
dispatch_queue_t myQueue = dispatch_queue_create("My Ticket Queue",NULL);
dispatch_async(myQueue, ^{
NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] init];
threadContext.parent = context; //assumes other context is NSMainThreadConcurrencyType
NSFetchRequest *ticketFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ticketEntity = [NSEntityDescription
entityForName:#"Tickets" inManagedObjectContext:threadContext];
[ticketFetchRequest setEntity:ticketEntity];
...
To get NSManagedObject between contexts use it's objectID property and [NSManagedObjectContext objectWithId:]
Should you make edits then you will need to save the thread context. Those changes will propagate automatically down to the parent context.
Otherwise you discard the context at the end of the block like a sheet of paper.
EDIT
Also if the count of the objects is the only thing you want then you can use
countForFetchRequest:error: on NSManagedObjectContext
This will be a cheaper call because no objects are created for you.
I landed into a weird problem where i cannot use array.count that crashes my app.
#interface LAMasterViewController ()
NSMutableArray * claimReports
#end
-(void) ViewDidLoad
{
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
-(NSArray *) getClaimReportsOrderedByIncidentDate
{ // it returns one record
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [ NSEntityDescription entityForName:#"ClaimReport" inManagedObjectContext:context];
NSSortDescriptor *sortByIncidentDate = [[NSSortDescriptor alloc] initWithKey:#"dateOfIncident" ascending:NO];
[request setEntity:entity];
[request setSortDescriptors: [NSArray arrayWithObject: sortByIncidentDate]];
NSArray *array = [context executeFetchRequest:request error:&error];
NSLog(#"Array Count %i" ,array.count);
return array;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count; //crashes here
}
error:
-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0
2014-04-01 14:56:29.022 LossAdjusting[6956:70b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0'
What have i missed here. Seems a silly one. please guide.
Thanks
Long-story-short, you are treating an instance of LSClaimReport as if it was an NSMutableArray instance.
The end.
EDIT OK, flippany aside, you are confused about instance variable and local variables and have confused the types of one of your instance variables.
In ViewDidLoad (case incorrect, so if that's copied verbatim then it won't even be called), you reference a local version of claimReports which is created and then thrown away:
-(void)ViewDidLoad
{
NSMutableArray *claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
and later you refer to the instance variable version:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count; //crashes here
}
Which is clearly a LSClaimReport instance and not a NSMutableArray.
So it looks like:
You have declared the wrong type in your #interface.
You are not initializing it correctly (you already fixed that bit).
please remove the local Arraydeclaration:
NSMutableArray * claimReports = [[NSMutableArray alloc] init];
instead use:
claimReports = [[NSMutableArray alloc] init];
In case this is no Class variable yet, add it to your #interface-declaration:
#interface LAMasterViewController ()
{
NSMutableArray * claimReports
}
#end
#implementation LAMasterViewController
Write this in your .h file
NSMutableArray * claimReports;
and in your .m
-(void)viewDidLoad{
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
You have few things wrong with your code which cleaning them up will help resolve the issue, the main issue '-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0' is because you are calling count on an instance of LSClaimReport which clearly shouldn't be happening. Your code seems to think that claimReports is an instance of LSClaimReport and not an instance of NSMutableArray.
As for your code may I recommend changing to (Please see comments in code marked issue)
#interface LAMasterViewController ()
// Clearly you want this as a private property so why would you want to change
// to having this in the .h file which would make it public
// But Issue 1 is here you are missing the semi-colon (`;`) of the end.
#property (nonatomic, strong) NSMutableArray *claimReports;
#end
// Issue two you are missing the `#implementation LAMasterViewController`
#implementation LAMasterViewController
// The synthesize is done automatically so getters/setters/ivar are created automatically
// Issue 3: ViewDidLoad isn't a valid selector so ViewDidLoad will never be called
// It is viewDidLoad
-(void)viewDidLoad
{
[super viewDidLoad]; // Issue 4: you missed the call to super
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate]];
}
-(NSArray *)getClaimReportsOrderedByIncidentDate
{ // it returns one record
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [ NSEntityDescription entityForName:#"ClaimReport" inManagedObjectContext:context];
NSSortDescriptor *sortByIncidentDate = [[NSSortDescriptor alloc] initWithKey:#"dateOfIncident" ascending:NO];
[request setEntity:entity];
[request setSortDescriptors: [NSArray arrayWithObject: sortByIncidentDate]];
NSArray *array = [context executeFetchRequest:request error:&error];
NSLog(#"Array Count %i" ,array.count);
return array;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count;
}
#end
I've been following this tutorial to a T, but when I run my app, it fails on launch every time with the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a
legal NSManagedObjectContext parameter searching for entity name
'ArticleInfo''
But I can't figure out what I'm doing wrong that would cause that. As a background for what I've done, I have the datamodel file with an entity called ArticleInfo with a bunch of attributes of different types (some transient, if that's of note). Following the advice of this article I subclassed NSManagedObject as ArticleInfo.
If it's worth noting, I made the preview, wordsInBody and progress transient in the datamodel (and I gave position a default value of 0 in the Data Model Inspector). So in the subclass I made custom getters as follows:
- (NSString *)preview {
[self willAccessValueForKey:#"preview"];
NSString *preview = [self primitiveValueForKey:#"preview"];
[self didAccessValueForKey:#"preview"];
if (self.body.length < 200) {
preview = self.body;
}
else {
preview = [self.body substringWithRange:NSMakeRange(0, 200)];
}
return preview;
}
- (NSNumber *)progress {
[self willAccessValueForKey:#"progress"];
NSNumber *progress = [self primitiveValueForKey:#"progress"];
[self didAccessValueForKey:#"progress"];
if (self.body.length == 0) {
progress = #100;
}
else {
progress = #(100 * [self.position intValue] / [self.wordsInBody intValue]);
}
return progress;
}
- (NSNumber *)wordsInBody {
[self willAccessValueForKey:#"wordsInBody"];
NSNumber *wordsInBody = [self primitiveValueForKey:#"wordsInBody"];
[self didAccessValueForKey:#"wordsInBody"];
if (!wordsInBody) {
__block int numberOfWordsInBody = 0;
NSRange range = {0, self.body.length};
[self.body enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
numberOfWordsInBody++;
}];
wordsInBody = #(numberOfWordsInBody);
}
return wordsInBody;
}
(Again, not sure if that's relevant.)
Now in my main viewcontroller class (the one that has the tableview I'm using NSFetchedResultsController for) I declared the property, and overrode its getter:
In .h:
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
In .m:
- (NSFetchedResultsController *)fetchedResultsController {
if (!_fetchedResultsController) {
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ArticleInfo" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:descriptor];
request.fetchBatchSize = 20;
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:#"Root"];
_fetchedResultsController = fetchedResultsController;
_fetchedResultsController.delegate = self;
}
return _fetchedResultsController;
}
But again, it keeps giving me that error on app launch. What exactly am I doing wrong that's causing that error?
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ArticleInfo" inManagedObjectContext:context]
Something here is nil. Log context and entity to see which one. Maybe your entity name in your model isn't "ArticleInfo" (typo?) or your app delegate has a problem creating the context.
I have a singleton Data Manager that has this method:
-(NSArray*)fetchItems
{
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Item" inManagedObjectContext:self.managedObjectContext];
NSError *error2;
NSFetchRequest *itemFetchRequest = [[NSFetchRequest alloc] init];
[itemFetchRequest setEntity:entity];
[itemFetchRequest setReturnsObjectsAsFaults:NO];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"order"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[itemFetchRequest setSortDescriptors:sortDescriptors];
NSArray *fetchedItems = [self.managedObjectContext executeFetchRequest:itemFetchRequest error:&error2];
return fetchedItems;
}
I then create some views based on the core data objects like this:
self.items = [dataManager fetchItems];
for (Item *item in self.items) { //Item is the NSManagedObject subclass
ItemView *itemView = [[ItemView alloc] initWithFrame:aFrame ];
[itemView layoutWithData:item];
[self.someView addSubview:itemView];
}
The ItemView's data gets set like this:
- (void)layoutWithData:(Item*)_data {
self.data = _data;
NSLog(#"ItemView data: %#", self.data); //not "fault" at this point
...
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setImage:data.image forState:UIControlStateNormal];
[btn addTarget:self action:#selector(tapDetected:) forControlEvents:UIControlEventTouchUpInside];
btn.frame = aFrame;
[self addSubview:btn];
}
At this point, the ItemView's data is defined and is not "fault". However, when a tap is detected like this:
- (void)tapDetected:(id)sender
{
NSLog(#"TAP: %#", self.data); //fault - see below
[self.delegate itemTapped:self.data];
}
I get something like this:
TAP: <Item: 0x879ce40> (entity: Item; id: 0x8798310 <x-coredata://8BE9ABFE-7C63-4ADD-9AD1-62B81C5AFF66/Item/p66> ; data: <fault>)
Why is the data "non-fault" at first and then "fault" later when I tap the ItemView and how can I fix it? This has been killing me all day...
EDIT: using this code I can confirm that the data is not a fault in the layoutWithData method, but is a fault in the tapDetected method:
NSLog(#"is fault? %i", self.data.isFault);
Why would it turn into a fault???
It may not really be a problem, but a fault that means that the data hasn't been read yet. Try doing the following before the fetch:
[fetchRequest setReturnsObjectsAsFaults:NO];
That way the data will be completely read.
See
Similar Question
Currently I have an entity named "Events" in a CoreData app. "Events" has one string property named "eventName".
In the -(void)viewDidLoad I am trying to Fetch all the "Events" objects and load their "eventName" by alphabetical order into a UIPickerView.
The ultimate end goal is through the use of a textField, buttons and the pickerView being add new objects in and remove unwanted objects out. Basically turning the UIPickerView into a UITableView. Currently I am able to save objects to the CoreData store, but am not able to pull them/their properties out into the UIPickerView.
I am willing and able to share the project source code to anyone who wants it, or is willing to look at it to help out.
thanks
Chris
-(void)update
{
NSMutableArray *array2 = [[NSMutableArray alloc] init];
CDPickerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *moc = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"callName" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSArray *array = [moc executeFetchRequest:request error:&error];
for (int i=0; i<array.count; i++) {
Event *theEvent = [array objectAtIndex:i];
NSString *StringOne = [NSString stringWithFormat:#"%#",theEvent.callName];
[array2 addObject:StringOne];
}
self.pickerData = array2;
[singlePicker reloadAllComponents];
}
-(IBAction)addCall{
CDPickerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *theEvent = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[theEvent setValue:callField.text forKey:#"callName"];
[context save:&error];
callField.text=#"";
[callField resignFirstResponder];
self.update;
}