Monday, May 12, 2014

Cappuccino Essentials

The information contained here is subject to change as I learn more about the Cappuccino framework.

This article frequently references "the tutorials."  The specific tutorial which is referenced most frequently can be found here: Cappuccino Tutorial: Photo Album Part 1


Essentials for the Cappuccino Framework

One cannot teach a child to run before that child can walk.  To teach walking or running before that same child can stand is ridiculous.  I feel as I go through the tutorials at the Cappuccino Project's website that I am being asked to run, when I cannot even stand.  Contained in this article is some essential functions and information that are important to understand before we talk about the UI elements, such as Views, Windows, Window Controllers and other such elements.


Content Rectangles, Bounds, and Frames

Early in the tutorials, we are faced with the concept of content rectangles and frames; later, we start seeing the idea of bounds.  They are thrown at us with absolutely no explanation.  From what I can decipher at this point, Content rectangles, frames, and bounds are functionally the same thing.  Each require a CGRect object to be created in order to satisfy the function requirements.  I may learn at a later date that they are different in what it is they define conceptually, and at that time I will update this article to reflect that new knowledge.

The purpose of these entities is to define shape and position of objects and for other objects which might be contained by these items.  Bounds tend to be more the container limits, whereas content rectangles and frames tend to define object shape.

We will address the creation of the CGRect object in a moment.  For now, it is important to note that many objects that require definition using a content rectangle also have a function called "sizeToFit", which allows us as programmers to be lazy.  For these objects, we are able to provide a rectangle with no shape and no location, and allow the content views to define the minimum width and height of the object.  Using this method, we still must worry about defining the objects location, but for that we can use either setFrameOrigin:(CGPoint)aPoint or a set method which allows the redefinition of the content rectangle or frame.


CGPoint, CGSize, and CGRect

Content rectangles, described above, require CGRect objects, but what are CGRect objects?

CGPoint

First, let us consider the CGPoint object.  The CGPoint object can be used when calling the setFrameOrigin:(CGPoint)aPoint method of many objects.  The point object defines a location in space within the display area.  Like most graphical systems, the origin is always to the top left of the reference area, x always increases as we move from left to right, and y always increases as we move from top to bottom.

The origin of this plane is not always the top left corner of the browser window, however.  The origin changes depending upon the view object you are working with.  The origin is always the top left corner of the containing view object.  Be careful though, because every displayed item is a subclass of CPView, which means that you must consider whether you are inserting that label into the dialogue window, the background window, or a window that is not even displayed.  If you are having trouble defining a point in reference to a certain view's area, you probably are working with a different idea of what the origin is than the program is actually using.

Make a CGPoint by calling the CGPointMake(xpos,ypos) function.  The point is just a location on the screen. It has no height and no width.

CGSize

Unlike CGPoint, which has no width and no height, CGSize has both width and height, but it does not have a location.  One can make a size in Cappuccino by calling the function CGSizeMake(width,height).

The CGSize object defines an area on the screen that is not location dependent.  It can be used with images, or collection items to define a minimum or maximum display area as the window automatically resizes when the user makes adjustments to the display area.

CGRect

The most useful spacial object is the CGRect, which is a combination of the CGPoint and the CGSize features. CGRect has the x and y coordinates of a CGPoint, which specify the top left corner of the space defined by the width and height of the area defined.  I do not know if CGRect is derived from CGSize or CGPoint, but it is easiest to think of CGRect as a child of each of these objects, functionally.  One can produce a CGRect object by calling CGRectMake(xpos,ypos,width,height), or CGRectMakeZero(), which is similar to calling CGRectMake(0,0,0,0).

CGRect objects can be used to define frames, bounds, and content rectangles.  Because of this, you will see the function CGRectMake and CGRectMakeZero frequently in Cappuccino tutorials.  That this same object is used is so many different ways is both a blessing and a curse, because it becomes harder to conceptualize the differences between frames, bounds and content rectangles when they are all defined by the same functional entity.  As I learn these differences, I will update these blog articles.


Delegates, a manner by which objects communicate state

In the tutorials offered at the Cappuccino-Project, the concept of delegate is glossed over.  I didn't really understand it at first.  How does one know when a delegate is needed?  How does one determine what functions will be called on a delegate object?

Objects that use delegates all implement the "setDelegate:" method.  It is a good idea to check the documentation on objects that you use to determine if there are some benefits to setting a delegate on them.

The relationship between an object and it's delegate is seemingly backward to me.  Often, in the tutorials, the object on which we set the delegate is part of a subordinate view.  For example, in the PhotoAlbum example, we have a CALayer object which contains a CPImage.  It would seem to me that the CALayer manipulates the CPImage, but the delegate relationship allows the image to manipulate the CALayer.  The delegate, therefore, becomes the target of function calls by the object on which we are calling "setDelegate", but when we set the CALayer as the delegate to a CPImage object, how do we know which functions we need to define?  What is the CPImage going to call on the CALayer?

To determine which functions will be called by an object on it's delegate, search the Objective-J file of the object (as apposed to the header file) for the string "respondsToSelector:".  The object checks the delegate with this method before functions are called, to verify that the requested functions exist prior to calling them. By determining which functions will be called on the delegate by the object, one can determine what the relationship should be between a delegate and it's corresponding object.

In the tutorials, CPImage uses a delegate relationship to communicate that it is ready for display.  A CALayer can offer itself as a delegate to a CPImage.  The Image calls the delegate when it is finished loading to say "do something with me."  If the CALayer is set as the delegate to a CPImage, when the image finishes processing the image file, the CPImage checks the CALayer using "respondsToSelector:@selector('imageDidLoad')" to determine if the CALayer (a.k.a. the delegate) has an imageDidLoad method.  The CPImage then calls the delegates implementation of "imageDidLoad" passing itself as an argument, and this gives the delegate an opportunity to determine what happens next.   In this specific example, the CALayer should tell the CPImage that it needs to display itself on the screen.  If the CALayer does not tell the CPImage to display itself after it is done loading, then the rendered image of the Layer will likely not include the image which was just processed.  This relationship between the image and the layer allows the layer to render independently of the image, so that if the image file contains an error, the layer still render's (without the image).

The CPImage object will call three functions on any object that is offered as a delegate: imageDidLoad, imageDidError, and imageDidAbort.  The delegate object does not need to implement all of these functions, but to make the delegate relationship useful, it should implement at least one.  Otherwise, there is no benefit from one object telling the CPImage that it will act as the delegate.

No comments:

Post a Comment