Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Cocoa Question (Beginner)

Cocoa Question (Beginner)
Thread Tools
Fresh-Faced Recruit
Join Date: Sep 2000
Status: Offline
Reply With Quote
May 6, 2001, 04:12 PM
 
I'm just learning how to program using cocoa, being experienced in C++. I walked through the CurrencyConverter tutorial, and thought I understood it pretty well, so I decided to write up an app on my own that is only marginally more difficult, where the user enters some info, and hits save, and that info is sent to be saved in a class, and the user can then edit some more, and hit revert to make all the data fields the same as when they were last saved, or save to replace the old info.

I'm having no trouble with the GUI parts, I understand the outlets and everything very well. I am having trouble going from the controller to the model, however. I am hoping someone with some experience in cocoa can help me out.

I created a class DataManager, which just has a bunch of data members, and two functions, getDataMembers, and setDataMembers. Pretty simple. All the data members are c-style strings. When I click the save info button on my window, the DataManagerController called the setDataMembers function of the DataManager....or I guess it sends the setDatamembers message to the DataManager (gotta get into the objC mindset!). I'm pretty sure this is the right approach.

Now, my question is, how do I initialize the DataManager class? Normally, I would make some constructor, in C++, I dont know what to do in ObjC. I take it some sort of init function....but do I need to allocate it too, or is that done automatically when I instantiate it in IB? When will it get called? When the nib file is unpacked?


Also, the same goes for the strings....I was thinking of using NSStrings instead of c style strings, but am not sure how to go about this. I dont see an assignment method in the NSString class, only functions which initialize a new string from an old one. I was expecting to find something taht would basically do a strcpy() from one NSString to another, but all the fucntions appear to init a string from a string....what happens to the old string? Is something like (pseudocode) this legal:
NSString* myString;
[ myString initStringWithString:"someString" ];
[ myString initStringWithString:"someOtherString" ];

It seems like the above would leave an allocated string floating, somewhere.

Anyhow, if someone can help me get a grip on this, it would be appreciated. I am getting close to understanding, but need a couple more pushes. If anyone else could point out some other tutorials in ascending difficulty/complexity with small steps between, that'd be great too.

Thanks to anyone/everyone in advance...

Spencer
     
Admin Emeritus
Join Date: Oct 2000
Location: Boston, MA
Status: Offline
Reply With Quote
May 6, 2001, 06:08 PM
 
If your DataManager is instantiated in IB, it's automagically allocated and initialized.
There's no real analogy to a constructor in C++, but sending alloc and init* methods offer the same functionality. For example:

[[NSString alloc] init] ... or
[[NSString alloc] initWithCString:"Moo!"];

Items are allocated and init'ed when the nib file is loaded.

--

NSStrings are referenced by a "@" in front of a C String, e.g. "This is a C -style string!" ... @"This is an NSString!." So something like this is legal:

NSString *foo = @"Foo!!!";

_However_, it's often much more useful to use NSMutableStrings rather than NSStrings. NSMutableStrings can be modified with stuff like appendString:.
"Against stupidity, the gods themselves contend in vain" (Schiller)
     
Fresh-Faced Recruit
Join Date: Sep 2000
Status: Offline
Reply With Quote
May 6, 2001, 07:02 PM
 
alright, that helps a little.

With NSStrings, I am still not sure how to use them.

if tf is a NSTextField, which of these is the proper way to assign its value to a NSString in the model class DataManager..

NSString *a;
NSString *b;
a = [ tf stringValue ];
*b=*[ tf stringValue ];

I only want the value of the object, so I am guessing b?

Will I generally be derefencing everything then? Or am I missing the point somehow.

Thanks again,

Spencer
     
Admin Emeritus
Join Date: Oct 2000
Location: Boston, MA
Status: Offline
Reply With Quote
May 7, 2001, 08:31 AM
 
a = [tf stringValue] will be fine. In Cocoa, nearly everything's a pointer. Rather than trying to copy the contents of what stringValue returns, you want to use them directly.

[tf stringValue] will give you a pointer to an NSString. Setting a pointer to that will let you reference it whenever you need.
"Against stupidity, the gods themselves contend in vain" (Schiller)
     
Fresh-Faced Recruit
Join Date: Sep 2000
Status: Offline
Reply With Quote
May 7, 2001, 10:14 AM
 
Thanks again, parralax, I'm getting there...

So Objects in ObjC are more like objects in Java, than in C? In other words, although everything is actually a pointer, treat it as though there are no pointers?

How is scope handled? If I have a function
{
SomeClass a;
a = [ someObject self ];
// do stuff w/ a here...

}

Is a "destroyed" when the function ends? I would assume from your previous response the answer is no, else it would be a complete headache trying to manage memory otherwise. I see no mention of anything in ObjC analogous to destructors, so does ObjC do reference counting and have automatic garbage collection ala Java? Or each a programmer responsible for reference counting themselves, and autoreleasing when appropriate?

Thanks again for bearing with me,

Spencer
     
Fresh-Faced Recruit
Join Date: Sep 2000
Status: Offline
Reply With Quote
May 7, 2001, 11:26 AM
 
Also, if I am passing around pointers, will the following not work?

someClass {
NSString* aString;
}

- (void)putAStringIntoNSString*)outString;
- (void)setAStringFromNSString*)inString;


The above is obviously just pseudocode, but you get the idea. Now, if I have a class that calls putAStringInto: and does some work with the string passed back, will the changes also occur in someClass's aString member? It seems like they will, being that what was passed is a pointer.

Anyway, thanks.

Spencer
     
Senior User
Join Date: Feb 2001
Location: Rochester, uk
Status: Offline
Reply With Quote
May 7, 2001, 12:40 PM
 
Originally posted by swcrissman:
So Objects in ObjC are more like objects in Java, than in C? In other words, although everything is actually a pointer, treat it as though there are no pointers?

How is scope handled? If I have a function
{
SomeClass a;
a = [ someObject self ];
// do stuff w/ a here...

}
Firstly, say SomeClass * a - all the objects have to be pointers, even if they behave like they're not

Is a "destroyed" when the function ends? I would assume from your previous response the answer is no, else it would be a complete headache trying to manage memory otherwise. I see no mention of anything in ObjC analogous to destructors, so does ObjC do reference counting and have automatic garbage collection ala Java? Or each a programmer responsible for reference counting themselves, and autoreleasing when appropriate?
No, it doesn't have garbage collection like Java. It use what's called retain-release, which is somewhere between manual like C/C++ and automatic like Java. retain adds one to the reference count, release takes one away, autorelease feels free to take one away whenever it pleases. alloc makes the count at one; when it reaches zero, the object is deallocated.

So when you put the object somewhere new, you retain it, and when you forget about it from somewhere, you release it.

I remember hearing somewhere that garbage collection could actually be added to ObjC kinda easily. But it's not there right now.


(who knows Objective-C but not Cocoa)
All words are lies. Including these ones.
     
Admin Emeritus
Join Date: Oct 2000
Location: Boston, MA
Status: Offline
Reply With Quote
May 7, 2001, 12:43 PM
 
SomeClass a;
is not valid code. It would have to be something like
SomeClass *a. The first will flag an error (something along the lines of "statically allocated objects are not supported"). The second will work, but you'll need to allocate and initialize it.
"Against stupidity, the gods themselves contend in vain" (Schiller)
     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
May 7, 2001, 04:37 PM
 
Objective-C objects are always dynamic, never static. Object references are pointers (like Java), and they're always declared with the '*', though they are never dereferenced.

Object creation is typically done by [[SomeClass alloc] init], or something similar using a different init method. This uses the +alloc class method inherited from NSObject to do the actual allocation, then whichever init method as appropriate for the class.

The various -init* methods are the closest thing to C++ constructors; they initialize a new instance with the given parameters. Since they are normal methods however, they are inherited from superclasses. Only one init method should ever really be called on an instance.

If you intantiate a custom object in InterfaceBuilder, it will use [[YourClass alloc] init] on it, so for your own initialization override the -init method to do what you need.

NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:30];
NSString *myString;

myString = @"Constant NSString";
[myArray addObject:myString];
myString = [textField stringValue];
[myArray addObject:myString];
[myArray addObject:[textField stringValue]];
myString = [[NSString alloc] initWithCString:"C String"];


Memory management doesn't use a garbage collector like Java's, as noted previously in this thread. It uses straight reference counting -- a -retain adds to the reference count, -release decrements it. When the count reaches zero, the -dealloc method is called on the instance. That's the method you should override to release any instance variables or other resources the object holds (remember to call [super dealloc] of course).

Objects returned by +alloc, plus objects returned from the various copy methods (-copy, -copyWithZone:, -mutableCopy, etc.), have an implicit retain on them.

-autorelease is sort of a delayed release; it puts the receiver in the current autorelease pool, which is flushed after each event cycle (at which point -release is called on the original object). It's used so that return values from methods are valid in the caller's scope without the caller having to worry about any of its memory management. Virtually all methods that return objects in the Cocoa APIs return autoreleased objects. It's possible to create your own local autorelease pools if you need to flush out temporary objects more often.

So, the short of it is: for every +alloc, -copy, and -retain, there should be a corresponding -release or -autorelease sent to it. The one major gotcha is retain loops -- don't do that. [A retain loop is when object A retains object B, and object B retains object A, or some larger similar loop.]

Further info can be found on the Stepwise site -- http://www.stepwise.com/Articles/Tec...-03-11.01.html

BTW, most classes have convenience creation methods that return autoreleased objects. [NSString stringWithCString:"sdfsad"] is short for [[[NSString alloc] initWithCString:"sdfsad"] autorelease].

As noted, autoreleased variables will go away at some point, so if you want to keep one around as an instance variable you'll need to retain it.

Code:
@interface FooClass : NSObject { NSString *fooString; } - (id)init; - (id)initWithString:(NSString *)aString; - (NSString *)fooString; - (void)setFooString:(NSString *)aString; @end @implementation FooClass - (id)init { return [self initWithString:nil]; } - (id)initWithString:(NSString *)aString { [super init]; fooString = [aString retain]; // or [self setFooString:aString] return self; } - (void)dealloc { [fooString release]; [super dealloc]; } - (NSString *)fooString { return fooString; } - (void)setFooString:(NSString *)aString { [aString retain]; [fooString release]; fooString = aString; } @end
You'll notice I retain the argument before releasing the existing instance variable just in case they're the same object.

Hope this all helps...
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 09:59 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2