This question is an ongoing one for my previous question.
I want to make a predicate to filter the entity by my customized property, this is the entity class
#interface Expense : NSManagedObject
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSNumber * amount;
#property (nonatomic, retain) NSString * category;
#property (nonatomic, retain) NSString * note;
#property (nonatomic, retain) NSString * paidby;
//customized property
#property (readonly) int year;
#property (readonly) int month;
#property (readonly) NSString *yyyy_mmm;
#property (readonly) NSString *mm_yyyy;
#end
And this is my predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"yyyy_mmm == %#", header];
When run:
error message NSInvalidArgumentException', reason: 'keypath yyyy_mmm
not found in entity
This is not completely unexpected, I searched and find out it has something to do with key-value, listener stuff. But I do not know what to do exactly.
Any help will be so appreciated, and BTW the coding block has some problem, please forgive me.
Make any property you need to use in the predicate an actual key on the entity in your data model. If you can set the value directly, great, do that. If not you either want to implement willSave or use KVO and update your predicate key values from the other values in your entity.
Related
https://github.com/lokming/QuestionBank
I have entities: Bank,Section,Subsection,Set,Question.
I am having problems accessing relationship "NSSet Subsection" in entity Section and getting the message "[UITableViewCell thesubsection]: unrecognized selector sent to instance" from this code
in CRSectionVC.m which fills a tableview cell
- (NSArray *)allQuestions
{
NSSortDescriptor *division = [NSSortDescriptor sortDescriptorWithKey:#"subdivision" ascending:YES];
return [_section2.thesubsection sortedArrayUsingDescriptors:#[division]];
}
I can however access the "NNSet section" relationship in Bank entity using this code
NSSortDescriptor *division2 = [NSSortDescriptor sortDescriptorWithKey:#"division" ascending:YES];
return [self.detailItem2.thesection sortedArrayUsingDescriptors:#[division2]];
_section2 is declared in CRSubsectionVC.h
#property (strong, nonatomic) Section *section2;
The storyboard is
1. CRMasterViewController which displays ‘category’ attribute from Bank entity into a tableview,
Bank.h
#class Section;
#interface Bank : NSManagedObject
#property (nonatomic, retain) NSString * category;
#property (nonatomic, retain) NSSet *thesection;
#end
Bank.m
#implementation Bank
#dynamic category;
#dynamic thesection;
#end
When I tap a ‘category’ I segue and pass a Bank object to CRDetailViewController. I use following code:
NSSortDescriptor *division2 = [NSSortDescriptor sortDescriptorWithKey:#"division" ascending:YES];
return [self.detailItem2.thesection sortedArrayUsingDescriptors:#[division2]];
to fetch section relationship (NSSet *thesection) ‘division’ attribute from Bank into tableview.
Section.h
#class Bank, Subsection;
#interface Section : NSManagedObject
#property (nonatomic, retain) NSString * division;
#property (nonatomic, retain) Bank *bank;
#property (nonatomic, retain) NSSet *thesubsection;
#end
Section.m
#implementation Section
#dynamic division;
#dynamic bank;
#dynamic thesubsection;
#end
If I tap a ‘section’ ’ I segue and pass a Section object to CRSubsectionVC named _section2. When I try to access NSSet *thesubsection to get ‘subdivision’ attribute using code
NSSortDescriptor *division = [NSSortDescriptor sortDescriptorWithKey:#"subdivision"ascending:YES];
return [_section2.thesubsection sortedArrayUsingDescriptors:#[division]];
I get the error [UITableViewCell thesubsection]: unrecognized selector sent to instance. I cannot figure out why automated accessor ‘thesection’ works OK but not ‘thesubsection’ .
Subsection.h
#class Section, Set;
#interface Subsection : NSManagedObject
#property (nonatomic, retain) NSString * subdivision;
#property (nonatomic, retain) Section *section2;
#property (nonatomic, retain) NSSet *set;
#end
Subsection.m
#implementation Subsection
#dynamic subdivision;
#dynamic section2;
#dynamic set;
#end
Fixed the problem. A case of not copying code exactly from working template and understanding core data and table views.
I have two related entities in core data
a book entity
#property (nonatomic, retain) NSString * author;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *reviews;
a review entity
#property (nonatomic, retain) NSString * reviewer;
#property (nonatomic, retain) NSString * reviewText;
#property (nonatomic, retain) Book *book;
the last property in each is the relationship.
I have a book object
Book *book
How do I fetch from CoreData all review object that are related to 'book'?
book.reviews should return a set of review objects for that book.
Can RestKit connect a relationship without storing the foreign key as an attribute, i.e., directly from the keypath in the JSON?
In particular, I've got a Job has_many Rooms relationship. The room's JSON doesn't contain the job, rather, both are loaded separately:
- job: {
id: 1,
name: "John"
}
- room: {
id: 4,
job_id: 1,
name: "spare bedroom"
}
The Job is loaded before the Room.
My CoreData models, Job has properties for
#interface Job : NSManagedObject
#property (nonatomic, retain) NSNumber * identifier;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *rooms;
#end
#interface Room : NSManagedObject
#property (nonatomic, retain) NSNumber * identifier;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Job *job;
#end
Currently I add a #property (nonatomic, strong) NSNumber *jobID; to Room, which I #synthesize.
JobMapping:
mapping = [RKManagedObjectMapping mappingForClass:[Job class]];
[mapping setPrimaryKeyAttribute:#"identifier"];
[mapping mapAttributes:#"name", nil];
[mapping mapKeyPath:#"id" toAttribute:#"identifier"];
[mapping mapRelationship:#"rooms" withMapping:[Room objectMapping]];
RoomMapping
mapping = [RKManagedObjectMapping mappingForClass:[Room class]];
[mapping setPrimaryKeyAttribute:#"identifier"];
[mapping mapAttributes:#"name", nil];
[mapping mapKeyPath:#"id" toAttribute:#"identifier"];
[mapping mapKeyPath:#"job_id" toAttribute:#"jobID"];
[mapping mapRelationship:#"job" withMapping:[Job objectMapping]];
[mapping connectRelationship:#"job" withObjectForPrimaryKeyAttribute:#"jobID"];
I was wondering if there's a way I can do this without the extra jobID property? I don't want to have a jobID attribute in the CoreData xcdatamodeld - it's redundant, as the relationship covers that.
Also if I rebuild the NSManagedObjects, I need to re-add the jobID property, which is tedious. Can't I tell restkit to connect the Room to its corresponding Job via the job_id keypath in the JSON?
If I remove the property, the mapKeyPath:#"job_id" line, and change the last line to [mapping connectRelationship:#"job" withObjectForPrimaryKeyAttribute:#"job_id"]; I get
the entity Room is not key value coding-compliant for the key "job_id".
I would make JobId a transient value in core data, and write a custom set and get for it.
The set would set the relationship to self.job=methodToReturnObjectMatchingJobId (this would be used by rest kit)
The get would return self.job.identifier
If you are not using mogenerator, I would suggest you have a look at it for all your core data needs.
Below is sample code of how i did it:
-(void) setClaimId:(NSNumber *)claimId{
Claim *propertyClaim=[Claim listItemFromId:[claimId intValue] withContext:self.managedObjectContext];
self.claim=propertyClaim;
}
-(NSNumber*) claimId{
return self.claim.referenceId;
}
where listItemFromId is a simple query that returns the object based on the id.
This has to be a common question and I found many related here in SO, but none with the solution for this.
I have these 2 coredata models:
#class Message;
#interface Conversation : NSManagedObject
#property (nonatomic, retain) NSString * number;
#property (nonatomic, retain) NSSet *messages;
#property (nonatomic, retain) Message *lastMessage;
And
#class Conversation;
#interface Message : NSManagedObject
#property (nonatomic, retain) NSString * account;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSString * message;
#property (nonatomic, retain) NSNumber * sentFlag;
#property (nonatomic, retain) NSString * status;
#property (nonatomic, retain) Conversation *conversation;
In my ConversationListViewController I fetch all conversations ordered by lastMessage.date.
Then the ConversationViewController receives a Conversationand lists its messages.
Right now I'm handling lastMessage manually, so every time I add a new message, in ConversationViewController, I also update conversation.lastMessage.
Is there a better way to do it?
Because right now, there's only one place I insert/update a new message, but if there was something like insert/update triggers that'd sound better..
I know I could fetch all Conversations and then sort them with a sortdescriptor using messages.#max.date but that doesn't sound like a good solution for a large pool of messages/conversations.
I really don't think that there is something more elegant or any kind of better way, then setting newMessage.conversation.lastMessage = newMessage.
Core Data posts notifications, every time it adds or changes an entity, but i don't think,that it would be easier to observe them, then adding this line of code every time you create a new message.
I can't figure this out. What I have read about transient properties tells me they can be identified in the object model with an undefined type. But the compiler complains about this with an error that the type is unknown.
From the Core Dat Programming Guide:
If the non-supported attribute is an object, then in the managed object model you specify its type as undefined, and that it is transient. When you implement the entity’s custom class, there is no need to add an instance variable for the attribute—you can use the managed object's private internal store. A point to note about the implementations described below is that they cache the transient value. This makes accessing the value more efficient—it is also necessary for change management. If you define custom instance variables, you should clean up these variables in didTurnIntoFault rather than dealloc or finalize.
Here is the header file:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class SearchTerms;
#interface SearchResult : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString * lattitude;
#property (nonatomic, retain) NSString * details;
#property (nonatomic, retain) NSString * endTime;
#property (nonatomic, retain) NSString * longitude;
#property (nonatomic, retain) NSString * city;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * imageLink;
#property (nonatomic, retain) NSString * startTime;
#property (nonatomic, retain) UNKNOWN_TYPE coordinate;
#property (nonatomic, retain) UNKNOWN_TYPE subtitle;
#property (nonatomic, retain) SearchTerms * searchUsed;
#end
I am trying to include the properties for an MKAnnotation with title, subtitle, and coordinate . Here, I need to derive subtitle from other fields, and derive coordinate from longitude and latitude.
I'm not sure how to reconcile what the Guide says and what looks plainly wrong, and the compiler says so.
Once I get the header right, I may be able to get the implementation right, and I'll use awakeFromFault to set the values. I'm not sure if I need to release the subtitle, which will be an NSString, using didTurnIntoFault, but that seems to be what the Guide says to do.
I haven't seen really good example of how to implement a simple transient property. I am tempted to jsut add the properties to the managed object entity and forget about mentioning it in the managed object model. But it seems that I would be overlooking something if I do that.
You need to change the property's type to id, or whatever is most suitable:
#interface SearchResult : NSManagedObject
{}
#property (nonatomic, retain) id coordinate;
#end
Another way to handle this is via KVC and dependent keys:
#implementation SearchResult
+ (NSSet *) keyPathsForValuesAffectingCoordinate
{
return [NSSet setWithObjects:#"latitude", #"longitude", nil];
}
- (id) coordinate
{
// Derive the coordinate value
}
#end
The problem here is that the MKAnnotation protocol stores its coordinate value in a CLLocationCoordinate2D which, is not an object but a struct and it does not support key-value coding. To use it as a transitional property, you will need to wrap it in an object.
The Core Data Programming Guide: Scalar Value Constraints
If you want to use a scalar type or structure that is not one of those
supported directly by Core Data and not one of the structures
supported by key-value coding, you must store it in your managed
object as an object—typically an NSValue instance, although you can
also define your own custom class. You will then treat it as an object
value as described later in this article. It is up to users of the
object to extract the required structure from the NSValue (or custom)
object when retrieving the value, and to transform a structure into an
NSValue (or custom) object when setting the value.