Re: Newbie Object Sharing Question
Re: Newbie Object Sharing Question
- Subject: Re: Newbie Object Sharing Question
- From: Ken Thomases <email@hidden>
- Date: Sat, 31 Jan 2009 13:09:58 -0600
On Jan 31, 2009, at 10:31 AM, Brian Slick wrote:
And I believe that I do understand the difference between objects
and pointers (I could be mistaken). The part I'm missing is what
this needs to look like in code. I'm afraid I need some handholding
here. If I knew what I needed to do in order for there to be only a
single data object referenced from multiple places, I wouldn't have
asked the question in the first place.
OK, so I recommend that you read a good introductory book on the C
language, followed by Apple's documentation on Objective-C (and maybe
a third-party book on that, too), then the Cocoa Fundamentals Guide.
Well, at the very simplest, here's a trivial example:
NSString* foo = [[NSString alloc] initWithUTF8String:"Here is some
text"];
NSString* bar = foo;
Now, we have two pointers, foo and bar, which both refer to the same
object, a string whose content is "Here is some text". The first
statement allocated and initialized the string object, and assigned
the pointer foo to refer to it. The second line assigned the pointer
bar to refer to the same object. The assignment copied the pointer,
but did not copy the object.
Let's suppose we create a custom class declared like so:
@interface ThingAMaBob : NSObject
{
NSString* incantation;
}
-(id)initWithMagicalIncantation:(NSString*)anIncantation;
@end
and defined like so:
@implementation ThingAMaBob
-(id)initWithMagicalIncantation:(NSString*)anIncantation
{
if (self = [super init])
{
incantation = [anIncantation retain];
}
return self;
}
-(void)dealloc
{
[incantation release];
[super dealloc];
}
@end
We might have code in some other part of our program which goes like
this:
NSString* magic = @"Abracadabra!";
ThingAMaBob* thing1 = [[ThingAMaBob alloc]
initWithMagicalIncantation:magic];
Now, magic contains a pointer to a string object. We're creating a
new ThingAMaBob instance and we've passed a reference to that same
string object into the initializer. Within the initializer there's
the parameter anIncantation which is a pointer which receives that
passed-in reference. We invoke the -retain message on that string
object, which returns a reference to that same string object back, and
we assign the instance variable "incantation" to point to it. So, now
we have three pointers (magic, anIncantation, incantation) which all
refer to the same object.
After the initializer returns, there are just two because
anIncantation is no longer in scope. But it's still the case that
"magic" and the "incantation" instance variable of our new ThingAMaBob
refer to the same string object.
If we then proceed to do:
ThingAMaBob* thing2 = [[ThingAMaBob alloc]
initWithMagicalIncantation:magic];
then much the same thing happens. After that line executes, the
string object is referred to by "magic", the "incantation" instance
variable of the ThingAMaBob instance pointed to by thing1, and the
"incantation" instance variable of the ThingAMaBob instance pointed to
by thing2. So, thing1 and thing2 are sharing a reference to a single
string object (here I used a bit of shorthand; I referred to the
objects pointed to by the two pointers by just mentioning the names of
the pointers).
A singleton implementation is _one_ solution to the issue you're
having, but it's not necessary, and not even recommended for
something as simple as this.
Can you expand upon why not? Based on the blog post I linked, it
sounds like this is exactly the situation in which to do this.
Well, in your original post you already pointed out that it seemed
much more complicated than necessary. Since you can achieve what you
need by simply passing references to an object around, creating a
singleton class is overkill.
It is sometimes appropriate to create a singleton, but it can be
somewhat limiting. If you start out writing a program using a
singleton class, and later realize you need more than one instance of
the class, you will discover that you need to rewrite a bunch of code.
One stumbling block is that you have two view controllers, but
evidently no central application controller. View controllers
should have logic and state specific to a view and that view's
relationship to the model. An application controller manages your
application overall. It manages the other controllers, including
your view controllers. It has the primary responsibility for
managing the application-global (as opposed to, for example,
document-specific) model, and for providing access to that model to
other parts of the program.
Well, I just used the Tab Bar Application template, and other than
the AppDelegate that doesn't contain very much, there is no provided
application controller. The need to create one was not immediately
obvious to me, as none of the examples in the book I'm reading
through have dealt with accessing the same data set in different tabs.
OK, that's why I explained it. ;)
I haven't done any coding for the iPhone, and I'm not familiar with
the templates that are provided for it.
In any case, since it provides an application delegate, you can (as I
suggested) combine the roles of application delegate and application
controller. You may, of course, expand upon the provided application
delegate class to give it additional functionality.
If it doesn't already have an applicationWillFinishLaunching: method,
you can create one. That is a good place to create/load your
application-global model. For example:
listItems = [[MyListItemArray alloc] init]; // Use whatever
initializer makes sense, if -init isn't right
// ... proceed to fill out some initial contents for the list, if
appropriate ...
Here, I'm assuming that listItems is an instance variable for the
application delegate/controller class. I'm also going to assume that
you declare a property of the same name, so other code will be able to
access the list.
I also do not yet see how this solves my problem. I need to see
some code. From my view controllers, I don't believe that I know
how to send messages to the AppDelegate (say, for the table data
source methods) without creating an instance, which I believe brings
me back around to the same problem I started with.
NSApp is a global variable referring to the one NSApplication object
in your program. NSApplication has a property called "delegate" which
refers to the application delegate object. Since we've just decided
(above) that the class of the application delegate object has a
"listItems" property, you can obtain a reference to the list items
from your view controller using this:
MyListItemsArray* theListItems = [[NSApp delegate] listItems];
You would have to have imported the header for your application
delegate class into the source file in order for the compiler to be
aware of the declaration of the listItems property.
Another approach I described would be to pass a reference to either
the application controller object or the list items array into the
initialize of the view controller in much the way I passed "magic"
into the initializer of ThingAMaBob earlier. Then, the view
controller would not need to use globals to find what it needs, it
would have references to that stuff via its instance variables. This
approach makes the code more flexible.
Thank you for the explanation, but I'm afraid I still have no idea
what I specifically need to do, or even what help topic to go search
on for additional instruction. The basic stuff about messaging I
have found so far all deals with creating new instances to send
messages to.
But surely it also shows passing pointers to objects into methods, and
implementing methods that receive such pointers as arguments, right?
And it shows classes which keep pointers to objects received via
parameters in instance variables. Right?
If not, then you haven't read even the Cocoa Fundamentals Guide. Or
you didn't recognize that what you were seeing included the basic
techniques you were looking for.
Regards,
Ken
_______________________________________________
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