• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Confusion
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Confusion


  • Subject: Re: Confusion
  • From: Bill Bumgarner <email@hidden>
  • Date: Sun, 24 Jun 2001 23:20:12 -0400

A simple clarification (I hope). This is the ANSI C type definition for the data type of id.

typedef struct objc_object {
Class isa;
} *id;

What this indicates is that the type "id" is a POINTER (hence the "*") to a structure that contains a single member; the isa. The isa is of type Class. Class is defined as:

typedef struct objc_class *Class;

That is, a Class is a pointer to a struct of type objc_class. objc_class is a struct that defines an objective c class.

At this point, we are deep in the bowels of the ObjC runtime-- someplace that most ObjC/Cocoa developers really never need to visit, but it is both very interesting and necessary to understand if one wants to have a Complete Picture of What is Really Going On.

---

The key to all of this is the isa. The isa is something that is common to everything ObjC. In particular, if you define:

id fooThing;
NSString *barThing;

This could be rewritten as:

struct objc_object *fooThing;
NSString *barThing;

And it would mean exactly the same thing. Now, look at the declaration for NSObject:

@interface NSObject <NSObject> {
Class isa;
}
.... methods here ...
@end

Ignore the <NSObject> for the moment-- it has to do with the methods implemented by NSObject and isn't important for this discussion. However, notice two things:

- NSObject does *not* declare a superclass. It is a root class.

- The first and only instance variable is exactly the same as the first and only instance variable in the objc_object structure. As far as the compiler is concerned, an (objc_object *) is pretty much identical to an (NSObject *).

--

Now, have a look at the declaration for objc_msgSend():

id objc_msgSend(id self, SEL op, ...);

This could be rewritten as:

struct objc_object *objc_msgSend(struct objc_object *self, SEL op, ...);

That is, objc_msgSend() is a function that takes at least two arguments-- the target of the method call and the name of the method to be invoked-- and generally returns a pointer (a reference) to an object. Generally indicates that sometimes a method returns an undefined value as is the case with a method that has a return type of (void). Actually, it is more confusing in that objc_msgSend() will actually return lots of different data types-- (char), (int), (float), etc...-- and the compiler takes care of doing the right thing. Great for compilation and writing code, sucks for dynamic diddling of the runtime.... but that is really neither here nor there in this context.

So, if you type:

x = [fooThing objectAtIndex: 12];

The compiler literally translates that to:

x = objc_msgSend(fooThing, @selector(objectAtIndex:), 12);

As a matter of fact, early implementations of ObjC were nothing more than an extension to the C precompiler. It literally would interpret the [fooThing objectAtIndex: 12] and turn it into the above function call.

The fact that fooThing is declared as a variable of type (id), declared as type (struct objc_object *), or declared as (NSArray *) makes no actual difference to the resulting compiled binary or to program execution. By specifying (NSArray *), it gives the compiler a hint as to the scope of methods that might be valid in that context.

--

To bring this back around...

The isa pointer contained within every instance-- be it declared any of the three ways demonstrated above-- contains all of the information used by the runtime to figure out what method to invoke. A Class is defined as:

typedef struct objc_class *Class;

And the objc_class struct as:

struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;

#if defined(Release3CompatibilityBuild)
struct objc_method_list *methods;
#else
struct objc_method_list **methodLists;
#endif

struct objc_cache *cache;
struct objc_protocol_list *protocols;
};

Relevant to this conversation, the isa pointer contains all of the information that describes the instance of whatever the (id) or (NSString *) or (struct objc_object *) points to! It contains everything necessary for the objc_msgSend() function to dispatch a message to the appropriate method implementation.

---

The key is to separate the concepts of "at compile time" and "at runtime". A lot of the above is "at runtime": that is, an object reference or pointer is passed off to objc_msgSend() along with the name of the method to be invoked and the arguments to be sent to the method. objc_msgSend() uses the isa information to find the implementation and execute it. There is no difference between (id) and (NSString*) at runtime.

At compile time, the difference is that the compiler uses the differences between (id) and (NSString *) to provide you-- the developer-- with as much information as is possible regarding what can and cannot be done to a particular object reference.

b.bum


  • Prev by Date: Re: Another dummy C question
  • Next by Date: Re: PB widget
  • Previous by thread: Re: Confusion
  • Next by thread: Re: Confusion
  • Index(es):
    • Date
    • Thread