Re: beginner's question: having problems with saving/loading
Re: beginner's question: having problems with saving/loading
- Subject: Re: beginner's question: having problems with saving/loading
- From: Gunnar Proppe <email@hidden>
- Date: Tue, 12 May 2009 12:34:27 -0700 (PDT)
I don't know from the information provided why your generic init is being called, but the name of the class, AppController, is a clue to me. I'd expect a class called AppController to have a single instance, which would control the whole app, not to be a class that represents data in documents. My guess is you've been following along some examples for a non-document-based app and instantiated this in your xib based on those. You wouldn't want to do that for document data.
Set a breakpoint on the generic init function and your initWithCoder: is the self pointer in the debugger the same or different when you break at these points?
For document data, you almost certainly don't want to call that class AppController. Instead, call it what the data represents. Eg. Employee (in this case, TestData or whatever). I suspect your trouble is in the MyDocument class and how it manages the data object (currently AppController).
There are a few problems with your initWithCoder. It shouldn't call initWithString. It *should* call super init (or [super initWithCoder:coder] if the super class conforms to NSCoding, or the super classes designated initializer if it doesn't).
Here's what I think it should look like:
-(id)initWithCoder:(NSCoder *)coder
{
if (self = [super init])
{ NSLog(@"initWithCoder is being called");
self.theString = [coder decodeObjectForKey:@"theString"];
NSLog(@"theString is %@", self.theString);
}
return self;
}
(If you don't like dot notation use setTheString.)
Some other issues with your code:
You should implement dealloc and call self.theString = nil to release theString.
Read about designated initializers:
http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple_ref/doc/uid/TP30001163-CH22-SW8
Usually the longest initializer is the designated initializer. Your init method should call initWithString with a default string value (eg. [self initWithString:@"untitled"]).
Your initWithString is technically correct but not idiomatic. The usual pattern is as I showed initWithCoder, above. It's best to avoid multiple return paths in general, especially in init methods. Also, you might as well use your synthesized setter for theString, which will do the retain for you (eg. self.theString = aString).
Finally, you forgot to release the old theString and retain the new string in displayString. Again, just use your nice, convenient, synthesized setter, and it'll do that housekeeping for you. You'd then also want to remove the willChangeValueForKey and didChangeValueForKey calls, since the setter also does that for you.
If you don't have it, I highly, highly recommend getting a copy of Cocoa Programming for Mac OS X by Aaron Hillegass. It's well worth the money, and it's a lot easier to learn from than the free online documentation available.
Gunnar
----- Original Message ----
> From: Gabriel Roth <email@hidden>
> To: email@hidden
> Sent: Monday, May 11, 2009 12:42:01 PM
> Subject: beginner's question: having problems with saving/loading
>
> In my attempt to learn Cocoa programming, I’m working on a tiny app to
> practice saving and loading files. Each document window contains a
> text field, a label, and a button. The user types a string into the
> text field and clicks the button, and the same text appears in the
> label. When the document is saved and reopened, the string that was
> saved with the document should appear in the label. Apart from saving
> and loading, the program works as I expect.
>
> The app contains just one class (besides MyDocument), called
> AppController. The code for AppController is pasted below, followed by
> console output.
>
> When loading a saved document, the application calls initWithCoder.
> This decodes the saved string and uses it in the initWithString
> method. According to log statements, the initWithString method is
> called successfully. But then the program calls the generic init
> method, which sets the string to NULL, so the label in the window
> reverts to the null placeholder set in the xib file.
>
> I don’t know what’s calling the generic init method, or how to prevent
> this from happening, or if I should be avoiding this problem some
> other way. Any explanation of this situation would be appreciated.
>
> === AppController.h ===
> #import
>
>
> @interface AppController : NSObject {
> NSString *theString;
> IBOutlet NSTextField *theInput;
> }
>
> @property (retain) NSString *theString;
> -(IBAction)displayString:(id)sender;
> -(id)initWithString:(NSString *)aString;
>
> @end
>
> === AppController.m ===
> #import "AppController.h"
>
> @implementation AppController
> @synthesize theString;
>
> -(IBAction)displayString:(id)sender
> {
> NSLog(@"displayString is being called");
> [self willChangeValueForKey:@"theString"];
> theString = [theInput stringValue];
> [self didChangeValueForKey:@"theString"];
> }
>
> -(void)encodeWithCoder:(NSCoder *)coder
> {
> [coder encodeObject:theString forKey:@"theString"];
> }
>
> -(id)initWithCoder:(NSCoder *)coder
> {
> NSString *aString = [[coder decodeObjectForKey:@"theString"] retain];
> NSLog(@"initWithCoder is being called");
> NSLog(@"aString is %@", aString);
> [self initWithString:aString];
> return self;
> }
>
> -(id)initWithString:(NSString *)aString
> {
> if (self = [super init]) {
> NSLog(@"initWithString is being called with string %@", aString);
> [self willChangeValueForKey:@"theString"];
> theString = aString;
> [theString retain];
> [self didChangeValueForKey:@"theString"];
> NSLog(@"theString is %@", theString);
> return self;
> }
> else
> return nil;
> }
>
> -(id)init
> {
> NSLog(@"generic init is being called");
> self = [super init];
> return self;
> }
> @end
>
> === console output from opening a file ===
>
> 2009-05-11 15:40:13.210 SaveTest2[26335:10b] readFromData called
> 2009-05-11 15:40:13.211 SaveTest2[26335:10b] initWithCoder is being called
> 2009-05-11 15:40:13.212 SaveTest2[26335:10b] aString is foo
> 2009-05-11 15:40:13.212 SaveTest2[26335:10b] initWithString is being
> called with string foo
> 2009-05-11 15:40:13.212 SaveTest2[26335:10b] theString is foo
> 2009-05-11 15:40:13.215 SaveTest2[26335:10b] generic init is being called
> 2009-05-11 15:40:13.217 SaveTest2[26335:10b] windowControllerDidLoadNib called
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden