I have this managedObject subclass, position rappresent a NSPoint. In a XIB I want two NSTextField like this
where one display position.x value and the other display position.y. I tried to bind the NSTextField to a "selection.position.x" and "selection.position.y" keyPath of a NSArrayController that manage Frames
I get this error::
[ setValue:forUndefinedKey:]: this class
is not key value coding-compliant for the key x.
So i checked KVC:
Frame.h
#interface Frame : NSManagedObject {
#private
}
#property (nonatomic, retain) NSNumber * order;
#property (nonatomic, retain) NSNumber *visible;
#property (nonatomic, retain) NSValue *position;
#property (nonatomic, retain) NSNumber *scale;
#property (nonatomic, retain) Sprite *sprite;
#property (nonatomic, retain) Resource *resource;
//test
#property (nonatomic, retain) NSValue *frame;
#end
In -(void)awakeFromInsert I try this code:
-(void)awakeFromInsert
{
[super awakeFromInsert];
self.position = [NSValue valueWithPoint:NSPointFromCGPoint(CGPointZero)];
//[self.position setValue:[NSNumber numberWithFloat:50.0f] forKey:#"x"];
[self setValue:[NSNumber numberWithFloat:1.0f] forKeyPath:#"scale"];
[self setValue:[NSNumber numberWithFloat:10.0f] forKeyPath:#"frame.origin.x"];
[self setValue:[NSNumber numberWithFloat:10.0f] forKeyPath:#"position.x"];
}
The first and second KVC setValue works, the third crash with the same message above
[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key x.
I don't understand why, any help is appreciate.
NSValue objects are not mutable. To change a NSValue property, you have to create a new NSValue object and then assign it to the property.
Related
I am obviously new in Core Data, I have read quite a lot about the topic from Apple and from countless other sources. However, none seems to treat the many-to-one relation in a way for a newbie like me to understand. I seems to be fine with one-to-one relation, but I have some difficulties on understanding many-to-one relation.
My problem is as follow:
I am working on a small project to practice Core Data. In my project, there are two entities:Person and Note and they are related as follow:
(Sorry, couldn't add the picture)
A Person can have several notes, but Note can only have one owner, Person. Person entity is related with a one-to-many relation (double arrows pointing to the entity: Note), while the entity Note is related with a many-to-one (single arrow pointing to Person)
This is what I have so far:
Note.h
#class Person;
#interface Note : NSManagedObject
#property (nonatomic, retain) NSDate * noteCreateDate;
#property (nonatomic, retain) NSString * noteUser;
#property (nonatomic, retain) Person *person;
Person.h
#class Note, Organise;
#interface Person : NSManagedObject
#property (nonatomic, retain) NSString * personAddress;
#property (nonatomic, retain) NSData * personAvatar;
#property (nonatomic, retain) NSString * personBDay;
#property (nonatomic, retain) NSDate * personFutureDate;
#property (nonatomic, retain) NSString * personGender;
#property (nonatomic, retain) NSString * personName;
#property (nonatomic, retain) NSString * personRelation;
#property (nonatomic, retain) NSSet *notes;
#property (nonatomic, retain) NSSet *organises;
#end
#interface Person (CoreDataGeneratedAccessors)
- (void)addNotesObject:(Note *)value;
- (void)removeNotesObject:(Note *)value;
- (void)addNotes:(NSSet *)values;
- (void)removeNotes:(NSSet *)values
In my view controller I am trying to save the notes as follow:
NSManagedObjectContext *context = [self managedObjectContext];
Note *newNote;
newNote = (Note *) [NSEntityDescription insertNewObjectForEntityForName:#"Note" inManagedObjectContext:context];
// Saving the notes
newNote.noteUser = noteTextView.text;
newNote.noteCreateDate = added;
[newNote setPerson:newNote.person];
///////////////Saving to the DataBase /////////
NSError *error = nil;
if ([self.managedObjectContext hasChanges]) {
if (![self.managedObjectContext save:&error]) { //save failed
NSLog(#"Save Failed: %#", [error localizedDescription]);
}
else {
NSLog(#"Save Succeeded");
}
}
It is saving the data in the database fine, but the problem is: There is no relationship between Person and Notes in the database. The column for person in the database is empty (not showing to whom the note belong to).
I have tried several things to try to link the person with the note, NONE of them seems to work. So, it seems that I am stucked and I would very much appreciate some help.
This is the latest tutorial I used for help:
http://brandontreb.com/core-data-quicktip-inverse-relationships
https://itunes.apple.com/fr/itunes-u/advanced-iphone-development/id407243028?l=en&mt=10
Thank you.
Your code does not create any relationship between the Note and a Person. This:
[newNote setPerson:newNote.person];
is the same as newNote.person = newNote.person; and does not change anything.
You must create a Person object (or fetch an existing Person) and then set
newNote.person = thePerson;
to establish the relationship.
I'm trying to make a XML-parser that saves data from YR.no-API. The parser should add data to these two datastructures. My problem is when i try to add a WeatherTimeData object to my array in WeatherData, it seems like the objects doesnt get added, the following count always give me zero
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"time"])
{
[self.weatherdata.timedata addObject:currentWeatherTimeData];
NSLog(#"amount of objects in timedata-array %d", [[self.weatherdata timedata] count]);
}
These are my two data-structures, i alloc weatherData in the following method
-(id) loadXMLByURL:(NSString *)urlString
{
_weatherdata = [[WeatherData alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
Do i have to alloc the array inside of the weatherdata object?
WeatherData.h
#interface WeatherData : NSObject
#property (strong, nonatomic)NSString *town;
#property (strong, nonatomic)NSString *country;
#property (strong, nonatomic)NSMutableArray *timedata;
#end
WeatherData.m
#implementation WeatherData
#synthesize town = _town;
#synthesize country = _country;
#synthesize timedata = _timedata;
#end
WeatherTimeData.h
#interface WeatherTimeData : NSObject
#property (strong, nonatomic)NSDate *startTime;
#property (strong, nonatomic)NSDate *endTime;
#property (strong, nonatomic)NSString *iconSymbol;
#property (strong, nonatomic)NSString *windDirection;
#property (strong, nonatomic)NSString *windSpeed;
#property (strong, nonatomic)NSString *temprature;
#property (strong, nonatomic)NSString *preassure;
#end
WeatherTimeData.m
#implementation WeatherTimeData
#synthesize startTime = _startTime;
#synthesize endTime = _endTime;
#synthesize iconSymbol = _iconSymbol;
#synthesize windDirection = _windDirection;
#synthesize windSpeed = _windSPeed;
#synthesize temprature = _temprature;
#synthesize preassure = _preassure;
#end
This type of problem is classically because the object hasn't been allocated, and given Objective-C allows messages to be sent to nil the programmer doesn't notice.
I think it would be nice to be able to provide a runtime environment variable where such events are logged to stdout...
I would suspect that [WeatherTimeData init] isn't creating timedata and that's because you haven't provided an implementation for it; just using #sythensize isn't enough to create the objects.
I need to use several times:
[mutableDict addEntriesFromDictionary:dictionary];
I don't know how to declare mutableDict in the header file. I try with:
#property (nonatomic, assign) NSMutableDictionary *mutableDict;
#property (nonatomic, retain) NSMutableDictionary *mutableDict;
#property (nonatomic, retain, readwrite) NSMutableDictionary *mutableDict;
And more...
How I must to declare this NSMutableDictionary??
In your header file use #property (nonatomic, retain) NSMutableDictionary *mutableDict; if your are not using ARC, or #property (nonatomic, strong) NSMutableDictionary *mutableDict; if you are using ARC.
In your implementation include #synthesize mutableDict; or better #synthesize mutableDict = _mutableDict; somewhere after #implementation YourClass.
You should also initialize it with something like _mutableDict = [[NSMutableDictionary alloc] init];
If you do not need your mutable dictionary used from outside (ex: [myobject.mutableDict addEntriesFromDictionary:dictionary]; you better not define it in your header file but in your implementation like:
#implementation YourClass {
NSMutableDictionary *_mutableDict;
}
and initialize it like shown above
I am new to Objective-c and Xcode, yet I believe I know enough about it to realize that something is going wrong here. I have an application using a storyboard, and one of the views in the application is not running its viewDidLoad method. I am not sure if this is relevant, but I had recently accidentally deleted my original storyboard, and had to make another one. The original had worked great with no problems, yet when I use the new one, it does not work. The view in question is also the first view of a Tab Bar Controller, which might be part of the problem.
Here is the code from the class responsible for the view (.h):
#import <UIKit/UIKit.h>
#interface TabSynth : UIViewController
#property (nonatomic, retain) IBOutlet UIImageView *tomeWater;
#property (nonatomic, retain) IBOutlet UIImageView *tomeFire;
#property (nonatomic, retain) IBOutlet UIImageView *tomeAir;
#property (nonatomic, retain) IBOutlet UIImageView *tomeEarth;
#property (nonatomic, retain) IBOutlet UIImageView *tomeDark;
#property (nonatomic, retain) IBOutlet UIImageView *tomeLight;
#property (nonatomic, retain) IBOutlet UIButton *airSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *darkSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *earthSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *fireSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *lightSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *waterSynthButton;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonLarv;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonAmoeb;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonLarv1;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonAmoeb1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeWater1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeFire1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeAir1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeEarth1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeDark1;
#property (nonatomic, retain) IBOutlet UIImageView *tomeLight1;
And here is the code from the (.m):
#import "TabSynth.h"
#implementation TabSynth
#synthesize tomeWater;
#synthesize tomeFire;
#synthesize tomeAir;
#synthesize tomeEarth;
#synthesize tomeDark;
#synthesize tomeLight;
#synthesize tomeWater1;
#synthesize tomeFire1;
#synthesize tomeAir1;
#synthesize tomeEarth1;
#synthesize tomeDark1;
#synthesize tomeLight1;
#synthesize airSynthButton;
#synthesize darkSynthButton;
#synthesize earthSynthButton;
#synthesize fireSynthButton;
#synthesize lightSynthButton;
#synthesize waterSynthButton;
#synthesize synthButtonLarv;
#synthesize synthButtonAmoeb;
#synthesize synthButtonLarv1;
#synthesize synthButtonAmoeb1;
-(void)viewDidLoad {
extern int gTomeAir;
extern int gTomeDark;
extern int gTomeEarth;
extern int gTomeFire;
extern int gTomeLight;
extern int gTomeWater;
extern int gAmoebaeNum;
extern int gLarvaeNum;
synthButtonAmoeb.hidden=YES;
synthButtonAmoeb1.hidden=NO;
synthButtonLarv.hidden=YES;
synthButtonLarv1.hidden=NO;
if (gTomeAir>0) {
tomeAir.hidden=NO;
tomeAir1.hidden=YES;
airSynthButton.hidden=NO;
}
if (gTomeDark>0) {
tomeDark.hidden=NO;
tomeDark1.hidden=YES;
darkSynthButton.hidden=NO;
}
if (gTomeEarth>0) {
tomeEarth.hidden=NO;
tomeEarth1.hidden=YES;
earthSynthButton.hidden=NO;
}
if (gTomeFire>0) {
tomeFire.hidden=NO;
tomeFire1.hidden=YES;
fireSynthButton.hidden=NO;
}
if (gTomeLight>0) {
tomeLight.hidden=NO;
tomeLight1.hidden=YES;
lightSynthButton.hidden=NO;
}
if (gTomeWater>0) {
tomeWater.hidden=NO;
tomeWater1.hidden=YES;
waterSynthButton.hidden=NO;
}
if (gAmoebaeNum > 0) {
synthButtonAmoeb.hidden=NO;
synthButtonAmoeb1.hidden=YES;
}
else {
synthButtonAmoeb.hidden=YES;
synthButtonAmoeb1.hidden=NO;
}
if (gLarvaeNum >= 1) {
synthButtonLarv.hidden=NO;
synthButtonLarv1.hidden=YES;
}
else {
synthButtonLarv.hidden=YES;
synthButtonLarv1.hidden=NO;
}
}
In the if statements, the external integers being called (gTome) were set equal to a number in the previous view. Any help at all would be great, and I apologize for the simpleness of my coding.
If it's not calling viewDidLoad, then the first thing to check is that in your storyboard you have properly set TabSynth as the custom class of your view controller. Also, I don't see an NSLog in your viewDidLoad method. How do you know it's not being called?
By the way, did you know that you can put non-UI objects in a nib or storyboard? I think this might help you simplify your code. For example, you could have a class ElementViews defined like this:
ElementViews.h
#interface ElementViews : NSObject
#property (assign, nonatomic) IBOutlet UIImageView *tome;
#property (assign, nonatomic) IBOutlet UIButton *synthButton;
#property (assign, nonatomic) IBOutlet UIImageView *tome1;
#end
and then in your TabSynth class, instead of three outlets for every element, you just have one outlet:
TabSynth.h
#class ElementViews;
#interface TabSynth : UIViewController
#property (nonatomic, retain) IBOutlet ElementViews *waterViews;
#property (nonatomic, retain) IBOutlet ElementViews *fireViews;
#property (nonatomic, retain) IBOutlet ElementViews *airViews;
#property (nonatomic, retain) IBOutlet ElementViews *earthViews;
#property (nonatomic, retain) IBOutlet ElementViews *darkViews;
#property (nonatomic, retain) IBOutlet ElementViews *lightViews;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonLarv;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonAmoeb;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonLarv1;
#property (nonatomic, retain) IBOutlet UIButton *synthButtonAmoeb1;
...
In your storyboard, you drag a generic "Object" (looks like an orange cube) into your TabSynth scene. Change its custom class to ElementViews and its identity label to Water Views. Connect the waterViews outlet of the TabSynth to this new ElementViews object, and connect the outlets of the ElementViews object to the three water views (the tome and tome1 image views and the synthButton button). Repeat for the other five elements.
Then you can simplify your viewDidLoad method like this:
- (void)configureElementViews:(ElementViews *)elementViews state:(int)state {
if (state > 0) {
elementViews.tome.hidden = NO;
elementViews.tome1.hidden = YES;
elementViews.synthButton.hidden = NO;
}
}
- (void)viewDidLoad {
extern int gTomeAir;
extern int gTomeDark;
extern int gTomeEarth;
extern int gTomeFire;
extern int gTomeLight;
extern int gTomeWater;
extern int gAmoebaeNum;
extern int gLarvaeNum;
synthButtonAmoeb.hidden=YES;
synthButtonAmoeb1.hidden=NO;
synthButtonLarv.hidden=YES;
synthButtonLarv1.hidden=NO;
[self configureElementViews:self.waterViews state:gTomeWater];
[self configureElementViews:self.fireViews state:gTomeFire];
[self configureElementViews:self.airViews state:gTomeAir];
[self configureElementViews:self.earthViews state:gTomeEarth];
[self configureElementViews:self.darkViews state:gTomeDark];
[self configureElementViews:self.lightViews state:gTomeLight];
}
ok but you must write [super viewDidLoad] at the beginning of the method -viewDidLoad to call the viewDidLoad of the Controller itself (the father or its predecessor in the hierarchy of object) before writing your superb code which create a derived version of -viewDidLoad.
voila, good luck.
I have one class that controls one window, and another class that controls a different window in the same xib, however, the second window never displays what it should.
In the first class I alloc and init the second class, then pass some information to it. In the second class it displays that data in the table view.
Yes, in the .xib I have all the connections set up correctly, I've quadruple checked. Also the code is correct, same with the connections, I've quadruple checked.
Edit: and yes, there's data in the arrays, and the classes are NSObjects.
Edit2: I kinda found the problem. For some reason, the array is filled with contents, but it's returning 0 as a count.
Edit 9000:
Here's the code:
Answer.h
#import <Cocoa/Cocoa.h>
#interface MSAnswerView : NSObject {
IBOutlet NSWindow *window;
NSArray *User;
NSArray *Vote;
NSArray *Text;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
.m
#import "MSAnswerView.h"
#implementation MSAnswerView
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#synthesize window;
-(void)awakeFromNib
{
[view setTarget:self];
[view setDoubleAction:#selector(bodydata)];
[view reloadData];
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text
{
Vote = array;
User = user;
Text = text;
if (window.isVisible = YES) {
[view reloadData];
[view setNeedsDisplay];
}
}
-(int)numberOfRowsInTableView:(NSTableView *)aTable
{
return [User count];;
}
-(id)tableView:(NSTableView *)aTable objectValueForTableColumn:(NSTableColumn *)aCol row:(int)aRow
{
if (aCol == voteCount)
{
return [Vote objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [User objectAtIndex:aRow];
}
else
{
return nil;
}
}
-(void)bodydata
{
int index = [view selectedRow];
[body setString:[Text objectAtIndex:index]];
}
#end
The problems in your code are numerous.
For one thing, this comparison in -setUpWithVoteCount:User:Text: is incorrect:
window.isVisible = YES
That should be the comparison operator, == not the assignment operator =.
Secondly, you are naming your ivars and methods incorrectly. Instance variables (in fact, variables of any type) should start with a lower-case letter. This is to distinguish them from class names. Check out the Apple coding guidelines.
I'd also suggest that a name like text is a bad name for a variable that stores a collection like an NSArray. Instead, you should name it something like textItems so it's clear that the variable represents a collection and not a single string.
Also, the class itself is poorly named. You have called it MSAnswerView but it's not a view, it's some type of window controller. At the very least call it MSAnswerWindowController. Better still would be to make it a subclass of NSWindowController and make it File's Owner in its own nib. This is the standard pattern for window controllers.
Your method -setUpWithVoteCount:User:Text: should really be an initializer:
- initWithVoteCount:user:text:
That way it's clear what it's for and that it should be called once at object creation time.
The main problem, however, is that you're not retaining the values that you pass in to your setup method. That means that if no other object retains a reference to them, they will go away at some indeterminate point in the future. If you access them at a later time, you will crash or at the very least receive bad data, which is what's occurring.
Of course, you must also add a -dealloc method in this case to ensure you release the objects when you're finished with them.
Putting all those suggestions together, your class should really look something like this:
MSAnswerWindowController.h:
#import <Cocoa/Cocoa.h>
//subclass of NSWindowController
#interface MSAnswerWindowController : NSWindowController <NSTableViewDataSource>
{
//renamed ivars
NSArray *users;
NSArray *voteCounts;
NSArray *textItems;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
//this is now an init method
- (id)initWithVoteCounts:(NSArray *)someVoteCounts users:(NSArray *)someUsers textItems:(NSArray *)items;
//accessors for the ivars
#property (nonatomic, copy) NSArray* users;
#property (nonatomic, copy) NSArray* voteCounts;
#property (nonatomic, copy) NSArray* textItems;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
MSAnswerWindowController.m:
#import "MSAnswerWindowController.h"
#implementation MSAnswerWindowController
//implement the init method
- (id)initWithVoteCounts:(NSArray*)someVoteCounts users:(NSArray*)someUsers textItems:(NSArray*)items
{
//this is an NSWindowController, so tell super to load the nib
self = [super initWithWindowNibName:#"MSAnswerWindow"];
if(self)
{
//copy all the arrays that are passed in
//this means we hold a strong reference to them
users = [someUsers copy];
voteCounts = [someVoteCounts copy];
textItems = [items copy];
}
return self;
}
//make sure we deallocate the object when done
- (void)dealloc
{
self.users = nil;
self.voteCounts = nil;
self.textItems = nil;
[super dealloc];
}
//this is called when the window first loads
//we do initial window setup here
- (void)windowDidLoad
{
[view setTarget:self];
[view setDataSource:self];
[view setDoubleAction:#selector(bodydata)];
}
//this is called when the view controller is asked to show its window
//we load the table here
- (IBAction)showWindow:(id)sender
{
[super showWindow:sender];
[view reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTable
{
return [users count];
}
- (id)tableView:(NSTableView*)aTable objectValueForTableColumn:(NSTableColumn*)aCol row:(NSInteger)aRow
{
if (aCol == voteCount)
{
return [voteCounts objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [users objectAtIndex:aRow];
}
return nil;
}
- (void)bodydata
{
NSInteger index = [view selectedRow];
[body setString:[textItems objectAtIndex:index]];
}
#synthesize users;
#synthesize voteCounts;
#synthesize textItems;
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#end