Noob: Accessing Structures from Cocoa Classes

Member
Posts: 21
Joined: 2007.09
Post: #1
I have been hacking away at the Texture Range sample from Apple and decided to try and move the timer from the GLView class to the controller class.

I ran into a roadblock though because the view want to know what time it is to display the frames per second and I cant figure out how to access the struct timeval stored in the controller instance from the view instance. The basic question is how do I get the structure values from one object to another?

I've tried:

Code:
@interface AppController : NSObject{

struct timeval cycle;

...}


+ (id) cycle   // Funny, AppController won't recieve this as an  - (id) method !?

@ end

//MEANWHILE IN AppController.m....

+ (id) cycle{

   return cycle

}

//HOWEVER IN MainOpenGLView.m....

@implementation MainOpenGLView...

- (void)displayMPixels{...

   struct timeval cycle_time = [AppController cycle];  

   // gives "ERROR: incompatible types in assignment."
    
}


From which I gather that I can't use dynamic typing to access the structure values. Am I overlooking/overthinking something?
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #2
The return type is id, which can be thought of as a generic pointer type to an ObjectiveC object. You need to set the return type to struct timeval.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #3
akb825 Wrote:The return type is id, which can be thought of as a generic pointer type to an ObjectiveC object. You need to set the return type to struct timeval.

Can you give me an example of such a statement? Is it something like:

return struct timeval cycle; ? (EDIT: This doesn't eliminate the error)

or does the accessor method need to be something other than (id) (I cant make a struct method, I've discovered).
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #4
Not sure I quite understand the question, but here's a quick example for timeval.

Code:
- (double)currentTime
{
    struct timeval time;
    
    gettimeofday(&time, nil);
    return (double)time.tv_sec + (0.000001 * (double)time.tv_usec);
}
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #5
You would need to declare the method
Code:
+ (struct timeval) cycle
Though in reality, you'd most likely want it to return a struct timeval * and return the address of cycle. You would then need to de-reference it when assigning it to cycle_time.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #6
akb825 Wrote:You would need to declare the method
Code:
+ (struct timeval) cycle
Though in reality, you'd most likely want it to return a struct timeval * and return the address of cycle. You would then need to de-reference it when assigning it to cycle_time.

This is what happens when someone tries to learn Obj-C without knowing C.

Thanks for the declaration, that was a permutation I didn't try. Not sure I get what you mean by the syntax "struct timeval *" but I guess I'll look it up and read up on de-referencing.

(EDIT) OK got it. "*" provides the a pointer. I probably should have mentioned that the structure cycle_time is actually the address &cycle_time. Does that make any difference here?

Another Jake,

Thanks but the method you suggest returns a double to the caller and I was trying to return the whole structure so that I could parse out its values from within the calling object as needed.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #7
You really need to learn C. I cannot stress how important it is to know about pointers, as well as other things such as structs and all the other C constructs. Do that first: it will help you greatly with ObjectiveC, especially when you have problems such as this.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #8
akb825 Wrote:You really need to learn C. I cannot stress how important it is to know about pointers, as well as other things such as structs and all the other C constructs. Do that first: it will help you greatly with ObjectiveC, especially when you have problems such as this.

Sure, point taken. In the mean time I hope that doesn't deter the nice folks here from answering my questions. I really do try and check these things out as best I can before I post.

[UPDATE]

Thanks again for your help. This site: http://www.cs.cf.ac.uk/Dave/C/node10.html walked me through the pointers address issue. For others confused about the syntax this is what finally worked for me.

Code:
struct timeval cycle;  //declare the predefined structure
...

+ (struct timeval *)cycle;

//  then in the implementation:

- (struct timeval *)cycle  //function to return pointer
{    

    return &cycle;    //return the address
    
}

// finally in receiving object

struct timeval cycle_time;   //declare structure

cycle_time = *[myAppCtrl cycle];    //assign contents of address returned


Not 100 percent sure on the dereferencing but this gives me a start. Now on to working out my initial object design issues...
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #9
I'm still confused as to why you're trying to pass a raw timeval around, which is why I put up my little example. In the real world you don't really need the ultra-fine precision of the full timeval struct, so the double is more than sufficient for most purposes.

Using (struct timeval *) as the return value means that you are passing back a pointer (an address) instead of a raw struct, so yes, cycle_time being a pointer matters greatly.

In a more awkward approach, you could try this with your existing id returned to displayMPixels (I wouldn't do it this way since id should be reserved for proper objects, but it's interesting to look at for educational purposes):

struct timeval cycle_time = *(struct timeval *)[AppController cycle];

[edit] gah, just woke up... had to fix a typo...
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #10
You can still have cycle_time not be a pointer perfectly fine, if you wanted to modify the value while keeping the internal one be the same. Example, using all the code he's provided so far:
Code:
@interface AppController : NSObject{

struct timeval cycle;

...}


+ (struct timeval *) cycle

@ end

//MEANWHILE IN AppController.m....

+ (struct timeval *) cycle{

   return &cycle

}

//HOWEVER IN MainOpenGLView.m....

@implementation MainOpenGLView...

- (void)displayMPixels{...

   struct timeval cycle_time = *[AppController cycle];  
    
}

If you don't want to modify cycle_time, however, it is indeed best to make it a pointer.

No, not knowing this stuff won't keep us from answering your questions. For a while, at least. Given enough simple questions, people will most likely get annoyed and tell you to learn it yourself. I don't mean to insult you in any way, but think of it this way: if somebody asked you what x + y is, then what x*y is, then what x/y is, and continue for 100 more questions, you will most likely tell the person at some point "why don't you learn basic arithmetic?" Along the same reasoning, we will be more than happy to help you learn the basics by giving you some resources to give you a head start and help you through the concepts you don't understand if you get stuck.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #11
And what I was saying just above, as an educational exercise to distort the way things should be done, you could do the same thing like this:

NOTE: don't do it this way, even though it'd work too.

Code:
@interface AppController : NSObject{

struct timeval cycle;

...}


+ (id) cycle

@ end

//MEANWHILE IN AppController.m....

+ (id) cycle{

   return (id)&cycle

}

//HOWEVER IN MainOpenGLView.m....

@implementation MainOpenGLView...

- (void)displayMPixels{...

   struct timeval cycle_time = *(struct timeval *)[AppController cycle];  
    
}
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #12
AnotherJake Wrote:
Code:
return &(id)cycle
Won't work. Needs to be:
Code:
return (id) &cycle;
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #13
Blush Whoops! That was another early morning typo, hehe...
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #14
AnotherJake Wrote:I'm still confused as to why you're trying to pass a raw timeval around, which is why I put up my little example. In the real world you don't really need the ultra-fine precision of the full timeval struct, so the double is more than sufficient for most purposes.

Thanks everyone for all the input. Jake, the reason I am passing the raw interval from the controller to the view is because the view instance wants to parse out the stucture values cycle_time.tv_sec and cycle_time.tv_usec in order to calculate and display frames per second. I don't know if the accuracy is needed but that is the way Apple wrote it up. Besides, I needed to figure out how to return structures anyway.

My objective was just to take the time keeping away from the view so that other views could ask for it without all the views having to keep their own timers or talk to each other (i.e. breaking the MVC paradigm).

As a last thought I had to go back and swap out AppController for [NSApp delegate] (which was set to AppController previously) so that I could use instance methods instead of class methods and get the structure pointer passed from my actual controller instance.

Next step is to figure out whether bindings are a better approach for me anyway.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #15
For any animation timing, doubles are way more than adequate. So for calculating fps you can definitely use the returned double I gave above -- it's what I use. That Apple example does it all funky IMHO. Look for other examples for calcing fps. And look for other examples for real time animation for games. Also, I don't know exactly what you're trying to do, but generally speaking it is better to keep a separate timer in each view. Strict MVC on the application level isn't really practical (in my experience) when dealing with real-time animation views since the system window manager has to coordinate drawing cycles.

PS, I'd stay away from bindings for now until you get the basics down pat.

[edit] Here's a quickly whipped up example of what you *might* do for your fps calculation:

(NOTE that this is completely untested and simply made up on the spot so it likely contains errors and will not work -- it's just for quick illustration)

NOTE2: The static variables are in the method here for brevity but really need to be instance variables instead.

Code:
- (double)framesPerSecond
{    
    static unsigned    frameCount = 0;
    static double    lastFPSUpdate = 0.0, fps = 0.0;
    double            currTime, deltaFPSTime;
    
    currTime = [self currentTime];
    deltaFPSTime = currTime - lastFPSUpdate;
    if (deltaFPSTime >= 0.5)
    {
        fps = (double)frameCount / deltaFPSTime;
        frameCount = 0;
        lastFPSUpdate = currTime;
    }
    frameCount++;
    prevFrameTime = currTime;
    return fps;
}
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  SQLite3 question: accessing by column instead of index? Toontingy 3 4,674 Apr 8, 2010 06:19 PM
Last Post: OneSadCookie
  C++ Interlocking Classes merrill541 1 2,685 Jan 25, 2009 08:43 PM
Last Post: akb825
  Accessing an inherited class's variables Tobs_ 22 10,241 Feb 28, 2007 05:26 PM
Last Post: mac_girl
  Trouble With Template Classes in C++ Nick 4 3,266 Nov 21, 2006 10:25 AM
Last Post: DoG
  Trouble with template classes ermitgilsukaru 2 2,723 Aug 11, 2006 02:00 PM
Last Post: ermitgilsukaru