One to Many Core Data binding issues - objective-c

I have 2 Core Data objects. Items and TimeLog. The items object has a one to many relation with TimeLog and I am using the IB and Array Controller to automatically populate the 2 NSTableView's
The top table view is for the items. When you select an item the bottom table should populate with the time logs.
However when I add an item, the application crashes with an error
<_NSFaultingMutableSet 0x102e0e790> addObserver:forKeyPath:options:context:] is not supported. Key path: date
I am using an Array Controller to populate all the information automatically. When I create and add and item I am not setting anything for the timeLog relationship because there is no time to add when they first add the item. The object is saving as I have logging that is triggered after the core data save event.
Items.h
#class TimeLog;
#interface Items : NSManagedObject
#property (nonatomic, retain) NSString * itemId;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * itemType;
#property (nonatomic, retain) NSSet *timeLog;
#end
#interface Items (CoreDataGeneratedAccessors)
- (void)addTimeLogObject:(TimeLog *)value;
- (void)removeTimeLogObject:(TimeLog *)value;
- (void)addTimeLog:(NSSet *)values;
- (void)removeTimeLog:(NSSet *)values;
#end
TimeLog.h
#class Items;
#interface TimeLog : NSManagedObject
#property (nonatomic, retain) NSString * time;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) Items *item;
#end
What is causing this error and how do I get rid of it?

I resolved this by creating another NSArrayController for my TimeLog and setting up the table like so.
TimeLog Arra Controller
Set Controller Content -> Content Set -> Bind to Items array controller. Model Key path to timeLog
Then each column of the table.

Related

Why declare the variables of public properties on the interface with the property declarations?

I'm looking at this code below and trying to figure out which of the two of us... (me, or the person who wrote it) doesn't know what they're doing.
Why did he/she declare properties, then declare matching variables as well?
I can't ask the person because this project is inherited from a group long gone.
#interface LayerList : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
UITableView *tvList;
ArcGisViewController *mapController;
NSArray *fileList;
}
#property (nonatomic, strong) IBOutlet UITableView *tvList;
#property (nonatomic, strong) ArcGisViewController *mapController;
#property (nonatomic, strong) NSArray *fileList;
-(void)visibleSwitchValueChanged:(id)sender;
-(IBAction) Cancel;
#end
This was the usual way in a day when you had to synthesize the properties manually before auto-synthesizing was introduced.

RestKit 0.20 mapping string array

So after reading this answer, I do not see how my case is any different, but the proposed solution just doesn't seem to work in RestKit 0.20.3
For the following json:
{
"photos": [
"872ac577-3f31-47a0-966e-6f2ed2fbabcd"
],
"imageUrl": [
"http://domain/WebAPI/FileUpload/10232013629_21382571406.439790.jpeg"
]
}
Mapping into the following object:
#class Picture, Site, Survey;
#interface Job : NSManagedObject
#property (nonatomic, retain) NSString * jobId;
#property (nonatomic, retain) NSString * jobName;
#property (nonatomic, retain) NSString * jobStatusId;
#property (nonatomic, retain) NSString * jobStatus;
#property (nonatomic, retain) NSString * projectId;
#property (nonatomic, retain) NSString * projectType;
#property (nonatomic, retain) NSString * siteId;
#property (nonatomic, retain) NSSet *surveys;
#property (nonatomic, retain) NSSet *photos;
#property (nonatomic, retain) NSDate *createdDate;
#property (nonatomic, retain) Site *site;
#end
Where photos is a Picture object that looks like this:
#interface Picture : NSManagedObject
#property (nonatomic, retain) NSData * data;
#property (nonatomic, retain) NSString * photoId;
#property (nonatomic, retain) NSString * pictureLoc;
#property (nonatomic, retain) NSString * imageUrl;
#property (nonatomic, retain) Job *job;
#property (nonatomic, retain) QuestionAnswer *question;
#end
I want to map the photos and imageUrl into the Picture's photoId and imageUrl, respectively. I thought I could use the following in my Job's mapping:
RKEntityMapping *ret = [RKEntityMapping mappingForEntityForName:#"Job" inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore ];
[ret addAttributeMappingsFromDictionary: #{
#"photos": #"photos.photoId",
#"imageUrl": #"photos.imageUrl",
}];
However, the mapped Job always ends up with nothing in the photos property.
I know that I am doing all the in-between steps correctly (like actually using ret for the mapping), as the JSON is a snippet that contains many other keys I am able to map with no problem. What am I doing wrong? please tell me
EDIT
Changed the mapping code as per Wain's answer:
RKEntityMapping *ret = [RKEntityMapping mappingForEntityForName:#"Job" inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore ];
RKEntityMapping *subMapping = [RKEntityMapping mappingForEntityForName:#"Picture" inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore ];
[subMapping addAttributeMappingsFromDictionary: #{
#"photos":#"photoId",
#"imageUrl":#"imageUrl"
}];
[ret addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:nil
toKeyPath:#"photos"
withMapping:subMapping]];
And now I get a Picture object added, but with nil for photoId and imageUrl (and yes, I checked to make sure I have the spelling and capitalization correct for the JSON keys)
The reason photos never has anything in it is that your mapping doesn't tell it to create a new object.
The problem is how you could tell it to create a single object and set both of the parameters into it. The problem is because you have 2 different arrays. The JSON I would expect you to have is 1 array which contains dictionaries with all of the details for that particular entry. RestKit can process both of the arrays but it would result in 2 distinct photo objects being created. To do this you need a second mapping with a nil key path and a relationship from ret to that new mapping.
An alternative could be to change the Job object so that it has 2 transformable (or transient) properties which are NSArrays. If you set ret to just map #"photos" : #"photos" and #"imageUrl" : #"imageUrl" then RestKit will map all of the data, just not into a photo object. You can then mutate this data after the mapping has completed if you want to...

Trying to set Core Data Relationships causing crash

I have a few entities, one named "List" and one named "Task". The both have multiple properties and only 1 relationship. The list property has a to-many relationship called hasTasks, whose destination is task.
This is the Task.h file that is generated for me.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Task;
#interface List : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSNumber * number;
#property (nonatomic, retain) NSNumber * tasks;
#property (nonatomic, retain) NSNumber * totalTime;
#property (nonatomic, retain) NSSet *hasTasks;
#end
#interface List (CoreDataGeneratedAccessors)
- (void)addHasTasksObject:(Task *)value;
- (void)removeHasTasksObject:(Task *)value;
- (void)addHasTasks:(NSSet *)values;
- (void)removeHasTasks:(NSSet *)values;
#end
Whenever I run a line of code such as :
[self.list addHasTasksObject:task];
it crashes my app without any error message. Any help would be appreciated.
I had this same problem and I fixed it in the .xcdatamodeld file. I had accidentally selected the ordered arrangement checkbox for a relationship without re-generating the NSManagedObject classes. Unchecking this box and re-building solved this problem for me. If you are still having a problem, try re-generating your NSManagedObject classes.

What causes -[__NSArrayM removeAllItems]: unrecognized selector while using Kal?

I have been working with Kal for 3 weeks. I was able to modify the holiday example to use my data and drill down. I am trying to create the simplest working process to build on.
I can display the calendar but when I try to mark dates I get an exception error:
On first starting this process I had a error about the delegate
I read that I needed to change from this
*/
#interface KalViewController : UIViewController <KalViewDelegate, KalDataSourceCallbacks>
{
KalLogic *logic;
UITableView *tableView;
id <UITableViewDelegate> delegate;
id <KalDataSource> dataSource;
NSDate *initialDate; // The date that the calendar was initialized with *or* the currently selected date when the view hierarchy was torn down in order to satisfy a low memory warning.
NSDate *selectedDate; // I cache the selected date because when we respond to a memory warning, we cannot rely on the view hierarchy still being alive, and thus we cannot always derive the selected date from KalView's selectedDate property.
}
#property (nonatomic, assign) id<UITableViewDelegate> delegate;
#property (nonatomic, assign) id<KalDataSource> dataSource;
#property (nonatomic, retain, readonly) NSDate *selectedDate;
TO THIS
#interface KalViewController : UIViewController <KalViewDelegate, KalDataSourceCallbacks>
{
KalLogic *logic;
UITableView *tableView;
__weak id <UITableViewDelegate> delegate;
__weak id <KalDataSource> dataSource;
NSDate *initialDate; // The date that the calendar was initialized with *or* the currently selected date when the view hierarchy was torn down in order to satisfy a low memory warning.
NSDate *selectedDate; // I cache the selected date because when we respond to a memory warning, we cannot rely on the view hierarchy still being alive, and thus we cannot always derive the selected date from KalView's selectedDate property.
}
//#property (nonatomic, assign) id<UITableViewDelegate> delegate;
//#property (nonatomic, weak) id <UITableViewDelegate> delegate;
//#property (nonatomic, weak) id <KalDataSource> dataSource;
#property ( weak) id <UITableViewDelegate> delegate;
#property ( weak) id <KalDataSource> dataSource;
#property (nonatomic, retain, readonly) NSDate *selectedDate;
Is this Correct Incorrect way of getting out of the delegate error?

NSPredicate for latest item in a collection

I have the following objects in my chat app (with one-to-many relationship)
#interface ChatEntry : NSManagedObject
#property (nonatomic, retain) NSString * text;
#property (nonatomic, retain) NSDate * timestamp;
#property (nonatomic, retain) ChatContext *context;
#end
#interface ChatContext : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * userId;
#property (nonatomic, retain) NSSet *entries;
#end
Each conversation (ChatContext) groups all messages send by this user (uniquely identified by userId field).
I'm trying to display a list of conversations which displays the last message of each conversation (similar to iMessage).
I'm using the following code:
NSFetchRequest* request=[[NSFetchRequest alloc] initWithEntityName:#"ChatEntry"];
request.predicate=[NSPredicate predicateWithFormat:#"timestamp=context.entries.#max.timestamp"];
request.sortDescriptors=[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"timestamp" ascending:NO]];
m_chat=[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:m_context sectionNameKeyPath:nil cacheName:#"chat"];
m_chat.delegate=self;
This works fine until I receive a new message (with NSFetchedResultsChangeInsert)
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
...
}
At that point, I get ANOTHER entry in my table view. The fetch controller keeps the previous entry (even though its timestamp is not the latest one anymore). I'm not sure how to solve this and force the controller to always evaluate the predicate.
Alternatively, I've tried to change my query to fetch ChatContext instances, but then I'm not sure how to actually read the latest entry in that context.
OK, I've managed to solve that. What I did is to add a "lastMessage" object to the context, which I keep updating on every new message. I then query the list of contexts, sorted by reversed lastMessage.timestamp. New messages update the lastMessage property in their context - which triggers an event and update the UI automatically.