Questions about structures


#1

At page 126 (the last sentence) you can’t send structures messages and you cant declare them as pointers.

  1. if we can’t messages send to structures why do we use center.x at page 129. center is a structure so how do send messages [center x] (dot notation)?

  2. We use CGContextRef = CGContext * , but the use of pointers wasn’t allowed for structure?

  3. Also why do we use bound.origin? What’s origin in this context? The origin of the frame or the iphone/ipad/ipad mini/ipod?


#2

3: See UIView Class Reference.

1 & 2:
The struct type is used for combining instances of other types, including instances of other struct types to derive a compound type. The instances in a struct are called members. Its members can be accessed by using the “.” operator when we have direct access to a struct instance or by using the “->” operator when we have a pointer to it.

We can also send messages to struct objects (instances of struct), but this requires writing extra code. In an objected oriented context, sending a message to an object usually means invoking or calling a function (or method) which takes the object as an argument. (This function has a very close association with the object instance.)

Here is a simple struct, Foo; you can send messages to its instances:
main.m

//  main.m

#import <Foundation/Foundation.h>
#import "Foo.h"

int main (int argc, const char * argv[])
{ 
    Foo *foo = FooCreate ();
    
    // send a message - invoke function with the object as an argument
    fooness_type fooness = (*foo->fooness)(foo);

    // send more messages - invoke functions with object as an arguments
    (*foo->setFooness)(foo, 0.7 * fooness);
    fooness = (*foo->fooness)(foo);

    FooRelease (foo);
    return 0;
}

Foo.h

//  Foo.h

#ifndef Foo_h
#define Foo_h

typedef double fooness_type;
typedef struct Foo Foo;

struct Foo
{
    fooness_type (*fooness)(const Foo*);
    void (*setFooness)(Foo*, fooness_type);
    
    struct Details * details;
};

Foo * FooCreate ();
void FooRelease (Foo*);

#endif

Foo.c

//  Foo.c

#include <stdlib.h>   // for malloc and free
#include "assert.h"   // for assert
#import "Foo.h"

// ------------------------------------------------
//
static fooness_type Fooness (const Foo*);
static void SetFooness (Foo*, fooness_type);

struct Details
{
    fooness_type fooness;
};

// Create a Foo object
Foo * FooCreate ()
{
    // Allocate memory
    //
    Foo *self = malloc (sizeof (*self));
    assert (self);
    
    self->details = malloc (sizeof (*self->details));
    assert (self->details);
    
    // Attach the methods
    self->fooness = Fooness;
    self->setFooness = SetFooness;
    
    // Initialize
    self->details->fooness = 22.0/7.0;
    
    return self;
}

// Release a Foo object
void FooRelease (Foo *self)
{
    free (self->details);
    free (self);
}

static fooness_type Fooness (const Foo *self)
{
    return self->details->fooness;
}

static void SetFooness (Foo *self, fooness_type v)
{
    self->details->fooness = v;
}

As an aside, the above example clearly highlights the benefits of using languages such as C++ and Objective-C; they relieve the programmer of writing a lot of (error prone) code by hand.


#3

The . operator in the C language is the structure access operator. It doesn’t send any messages, in fact, it just offsets memory by a some predetermined value. The problem with the . is that in Objective-C, it means something entirely different: send a message. So a . with a C structure and a . with an Objective-C object actually resolve into two different things. Confused? You should be - the dot is stupid and confusing.

You can use a pointer for a structure. You can use a pointer for anything. It’s just that there isn’t any point to do it for CGPoint, CGRect, and friends.

CGPoint p = CGPointMake(0, 0);
CGPoint *pPtr = &p;

That’s because CGPoint and friends are created on the stack or in the memory of an object and don’t have references to other objects. This allows them to be automatically destroyed without any negative side effects. CGContext, however, has references to other objects and must be memory managed. Therefore, you cannot create CGContexts on the stack, only on the heap. In order to reference an object in the heap, you must have a pointer to it.

The origin in this case is just 0,0, which refers to the top-left corner of the view that is running drawRect:.