Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Chirone

macrumors 6502
Original poster
Mar 2, 2009
279
0
NZ
I've a property called propertyOne

it exists in the data model the class is based off..

in the header it's declared as
Code:
@property (nonatomic, retain) NSString * propertyOne;

in the implementation it's put in as
Code:
@dynamic propertyOne;

in the implementation i made the set method:
Code:
-(void)setWords: (NSString*)newPropertyOne {
	[self willChangeValueForKey: @"propertyOne"];
	propertyOne = newPropertyOne;
	[self didChangeValueForKey: @"propertyOne"];
}

so according to the documentation i should be all sweet.
but no
undo works fine, but as soon as i do a redo it doesn't
Code:
(
    <MenuItem: 0x1296a0 Use Default>,
    <MenuItem: 0x129720 Use None>,
    <MenuItem: 0x1297a0 Use All>
)
that string is the new value of propertyOne after a redo

the best part is that the program can undo and redo perfectly if it's just undoing and redoing the awakeFromInsert.... *sarcasm*

what have i done wrong?
 
I've a property called propertyOne

it exists in the data model the class is based off..

in the header it's declared as
Code:
@property (nonatomic, retain) NSString * propertyOne;

in the implementation it's put in as
Code:
@dynamic propertyOne;

in the implementation i made the set method:
Code:
-(void)setWords: (NSString*)newPropertyOne {
	[self willChangeValueForKey: @"propertyOne"];
	propertyOne = newPropertyOne;
	[self didChangeValueForKey: @"propertyOne"];
}

so according to the documentation i should be all sweet.
but no
undo works fine, but as soon as i do a redo it doesn't
Code:
(
    <MenuItem: 0x1296a0 Use Default>,
    <MenuItem: 0x129720 Use None>,
    <MenuItem: 0x1297a0 Use All>
)
that string is the new value of propertyOne after a redo

the best part is that the program can undo and redo perfectly if it's just undoing and redoing the awakeFromInsert.... *sarcasm*

what have i done wrong?

There are two reasons why it doesn't work (+ a comment):
First reason: "setWords" should be "setPropertyOne". Otherwise the compiler is still generating its own set and get functions, as you have asked it to do via "@dynamic propertyOne;".
If you change "setWords" to "setPropertyOne", my guess is that undo and redo will work in all cases.

Comment: you are not doing anything special with "newPropertyOne". There is no reason why you should overwrite it. The standard method, generated by the compiler, will do just fine. Of course, if you want to special things to it, you have to overwrite it. But in this case use the correct name: "setPropertyOne".

Second reason: why is undo/redo working with "awakeFromInsert"? Because coreData automatically supports undo and redo, when you use the correct "setPropertyOne" function.
If you want to change values in another function, or your own implementation, then you also have to tell the undoManager how to undo your operation. You changed the value, but did not register the change with the undoManager. Type in "Undo Manager" in your Xcode documentation for more information. When you know how to do undo, you get redo for free.

That is why I think it is going wrong.
 
There are two reasons why it doesn't work (+ a comment):
First reason: "setWords" should be "setPropertyOne". Otherwise the compiler is still generating its own set and get functions, as you have asked it to do via "@dynamic propertyOne;".
If you change "setWords" to "setPropertyOne", my guess is that undo and redo will work in all cases.

Comment: you are not doing anything special with "newPropertyOne". There is no reason why you should overwrite it. The standard method, generated by the compiler, will do just fine. Of course, if you want to special things to it, you have to overwrite it. But in this case use the correct name: "setPropertyOne".
ah woops, that was a typo for setWords. it is already setPropertyOne and it still breaks the redo even when spelt correctly

it's true that in that example i'm not doing anything special. But in the actual code I am. however i removed the code that was special, so that only what i typed above is there in the setPropertyOne method (that was mistakenly typed as setWord) and it still broke the redo
the redo would still not work correctly

Second reason: why is undo/redo working with "awakeFromInsert"? Because coreData automatically supports undo and redo, when you use the correct "setPropertyOne" function.
If you want to change values in another function, or your own implementation, then you also have to tell the undoManager how to undo your operation. You changed the value, but did not register the change with the undoManager. Type in "Undo Manager" in your Xcode documentation for more information. When you know how to do undo, you get redo for free.

That is why I think it is going wrong.

i was under the impression that the
Code:
[self willChangeValueForKey: @"propertyOne"];
and
Code:
[self didChangeValueForKey: @"propertyOne"];
took care of the undo/redo part and doing the correct stuff in the undo manager, as that's all that is needed in the utility example/tutorial provided by apple which tells you how to write the get/set methods for the properties
 
i was under the impression that the
Code:
[self willChangeValueForKey: @"propertyOne"];
and
Code:
[self didChangeValueForKey: @"propertyOne"];
took care of the undo/redo part and doing the correct stuff in the undo manager, as that's all that is needed in the utility example/tutorial provided by apple which tells you how to write the get/set methods for the properties

You are probably right about that.
 
well.. that doesn't explain why it doesn't work then :(

I haven't done much with undo/redo, so this is just pure speculation.

Do you at some point in your program use your own NSUndoManager? Maybe there is a conflict between your manager and the NSUndoManager of coredata.
 
May of may not make a difference in your case, but you're supposed to use - (void)setPrimitiveValue: (id)value forKey: (NSString *)key when overriding a Managed Object's setter. Failing that, I'd see if removing the overridden method completely helps.
 
MrFusion: nah, i'm not using my own undo manager at any point, i figured the core data one would be enough

May of may not make a difference in your case, but you're supposed to use - (void)setPrimitiveValue: (id)value forKey: (NSString *)key when overriding a Managed Object's setter. Failing that, I'd see if removing the overridden method completely helps.

10,000 praises to ye!

you saved my life!!

thanks JoshDC!! :D

also, thanks for your input MrFusion :D
 
actually, that method is never called at all..
o_O

Maybe it is time for a more drastic step? Create a new coredata project and start adding the code from your old one that is related to the problem at hand. For every method you replace or add, you test the undo/redo functionality until you get the same problem. When you know which function is giving the problem, edit out the lines until it starts working again.

When you reach that point, report back to us and post all the code you have and line of code is giving all the problems.
Sometimes starting over helps (you see the problem).
 
hmm... i'm pretty stuck for time... :(
i think i'm going to have to write this thing old school without undo and saving... kind of a pain in the ass that i still can't resolve these issues... guess it'll have to wait for the next time...

a whole lot of thinks aren't working now like bindings..

but nonetheless... if someone tries doing this and succeeds please tell me :)
 
Sorry, I think you misunderstood me (and I can see why). What I meant was instead of the line:

Code:
propertyOne = newPropertyOne;

You should use:

Code:
[self setPrimitiveValue:newPropertyOne forKey:@"propertyOne"];
 
ah yes, that works now

this is really WEIRD though, because i swear i tried that before... maybe i did it differently...

thanks again for your help JoshDC, greatly appreciated!!!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.