TweetFollow Us on Twitter

May 92 - Exception Handling in MacApp 3

Exception Handling in MacApp 3

Lonnie Millett

One of the reasons MacApp is successful with developers is that applications built with MacApp can recover and continue operating under conditions that cause other applications to crash. What's the key to creating applications that never crash? It's called exception handling, and understanding how it works is the key to making your own applications fail-safe.

An exception can be defined as any condition which your code cannot be expected to cope with. One common type of exception occurs when trying to allocate memory when there is no memory available. Exception handling "…provides a way of transferring control and information to an unspecified caller that has expressed willingness to handle exceptions of a given type."[1] An exception handler that has expressed willingness to handle a memory exception may be responsible for cleaning up allocations that were made previous to the allocation that failed.

This first article will focus on the mechanics of exception handling in MacApp. By mechanics I am referring to the different usage styles, differences between C++ and Pascal, how it works internally, why and when variables need to be declared VOLATILE, etc. With the mechanics established, a second article will focus on the "how to" of exception handling: when it is needed, when it is not needed, where it goes, and how to introduce it into existing code.

Styles of Exception Handling in MacApp

In MacApp there are two styles of exception handling. The original style of exception handling available since MacApp 1.0, I will refer to as Pascal Style exception handling. It was designed to be used with Object-Pascal and relies on local or global procedures to handle an exception. With MacApp 3.0 a new style of exception handling has been introduced which I will refer to as C++ Style exception handling. Rather than relying on local procedures, it handles an exception within the else clause of an if statement. Neither style of exception handling is exclusive to the language it was designed for. Instances of Pascal style exception handling can be found in the C++ version of MacApp, and C++ style exception handling can be used from Pascal.

Pascal Style Exception Handling

Pascal style exception handling relies on the ability of Pascal to define local procedures as handlers as a way to have access to local variables, procedure parameters, or instance variables. A typical exception handler in Pascal would look like:
PROCEDURE TPicture.IPicture(…);

    VAR fi:     FailInfo;

    PROCEDURE HandleFailure(error: OSErr; message:LONGINT);
    BEGIN SELF.Free; END;

BEGIN
    …
    CatchFailures(fi, HandleFailure);
    fDataHandle := GetPicture(fRsrcID);
    FailResError;
    Success(fi);
    …
END;

We start by declaring an instance of a FailInfo record to contain the information needed by the exception handling services. Among the information stored in the FailInfo record are the current state of all the registers and the address of the procedure that will handle the exception. Later on we will look at the definition of FailInfo in detail. Next we define the local procedure that will be called should an exception occur. Because this is an IMethod, we will want to free ourselves if we can not completely initialize ourselves. In this case the body of the local procedure simply calls SELF.Free. With these two pieces defined we are ready to execute the code that could fail.

In Pascal you bracket any code that could fail with a calls to CatchFailures() and Success(). CatchFailures() requires two parameters: the FailInfo record to store the information necessary to handle the exception and the name of the local procedure to call should an exception occur. CatchFailures() is responsible for storing in the FailInfo record the information needed to pass control to an exception handler. It also installs or links the exception handling information to a list of exception handlers. In the above example, if the call to GetPicture should fail with a resource error, our local procedure HandleFailure() will be called, allowing us to clean up after ourselves. If we successfully retrieved the picture, then we finish our bracketing of the code that could fail with a call to Success(), passing it the same FailInfo record that we passed to CatchFailures(). Success() is responsible for removing the exception handling information from the list of installed exception handlers.

The Exception Handling Chain

MacApp maintains a chain of exception handlers in a linked list, with the current, or last installed, exception handler pointed to by the MacApp global variable gTopHandler. This means that there may be more than one active exception handler installed at any point in time, each scoped to perform certain tasks should an exception occur. This is important. It allows you to define exception handlers that can handle an exception at the local level and not worry about how the exception should be handled at an outer level.

So how does it work? After control is passed to the current exception handler, we usually want the exception to be passed to the other exception handlers in the chain so we can continue to handle the exception in the appropriate manner. With Pascal style exception handling, i.e. when the exception handler is installed with CatchFailures(), this happens automatically. When the global routine Failure() is called, gTopHandler is made to point to the next exception handler in the chain:

pascal void Failure(short error, long message)
{
    FailInfoPtr pf = gTopHandler;

    if (pf)
    {
        // pop the stack first, because calling the handler
        // is likely to result in a call to another call to
        // Failure
        gTopHandler = pf->nextInfo;
        …
        pf->error = error;
        pf->message = message;
        DoFailure(pf);  // Go execute the failure handler
        …

The call to DoFailure() is responsible for passing control to the currently installed exception handler. For Pascal style exception handling, as in our example, DoFailure() would call the local routine HandleFailure(). Following the call to HandleFailure(), DoFailure() calls Failure() once again with the same error and message:

   …
    MoveA.L (A0)+,A0        ; get address of failure handler
    
    Jsr         (A0)        ; call failure handler
                            ; (HandleFailure in our example)

    MoveM.L (SP)+,D0/D1     ; get error & message back
    Move.W  D0,-(SP)
    Move.L  D1,-(SP)        ; parameters to Failure
    Jsr     FAILURE         ; Pass the exception to next
                            ; handler
                            ; should Not return

gTopHandler already points to the next exception handler, so another call to Failure() will pass the exception to the next exception handler in the chain.

If you build debug versions of your MacApp applications you have probably seen something similar to this at one time or another:

Failure caught by: TAPPLICATION.OPENOLD
Failure caught by: CArrayIterator::IArrayIterator(…)
Failure caught by: TODOCCOMMAND.DOIT
Failure caught by: TCOMMANDHANDLER.PERFORMCOMMAND
Failure caught by: TAPPLICATION.POLLEVENT

When an exception occurs, part of the debugging information sent to your favorite source code debugger is a description of the exception stack or chain. Each entry in the list represents a currently installed exception handler. In the example above, TApplication::OpenOld was the last exception handler installed.

The last exception handler in the chain for a running application is usually installed in TApplication::PollEvent. When this exception handler is reached, MacApp assumes that all efforts to handle the exception have already occurred. The only task left is to display the appropriate error alert. After the alert has been displayed, the exception is fully handled, so MacApp continues by processing the event.

What if we don't want to pass the exception to any other installed exception handlers? This might be the case if we can completely handle an exception locally. Since Pascal style exception handling automatically propagates the exception, we have to break the propagation with a Pascal GOTO:

PROCEDURE TPicture.IPicture(…);
    LABEL 1;
    VAR fi:     FailInfo;

        PROCEDURE HandleFailure(
            error: OSErr; message:LONGINT);
        BEGIN
        SELF.Free;
        GOTO 1;
        END;

    BEGIN
    …
    CatchFailures(fi, HandleFailure);
    fDataHandle := GetPicture(fRsrcID);
    FailResError;
    Success(fi);
1:
    …
    END;

As we saw earlier, DoFailure() will call our exception handler, HandleFailure() in this example, if some resource error should occur. Rather than returning to DoFailure() and calling Failure() to propagate the exception, we instead jump to a label we have defined and continue executing from that point without ever returning.

C++ Style Exception Handling

With MacApp 3.0 a new style of exception handling was introduced. Unlike Pascal style exception handling, C++ exception handling is encapsulated in an if statement rather than a local procedure:
pascal void TPicture::IPicture(…)
{
    …
    FailInfo fi;

    if (fi.Try())
    {
        this->SetPictureRsrcID(itsRsrcID, kDontRedraw);
        fi.Success();
    }
    else    // Recover
    {
        this->Free();
        fi.ReSignal();
    }
    …
}

We start as we do in Pascal by declaring an instance of FailInfo. In C++ the FailInfo record of Pascal has been redefined as a C++ class. This class is not derived from TObject and is allocated locally on the stack. We are now ready to bracket the code that could potentially fail. The Try() method of FailInfo has the same responsibilities as CatchFailures() in Pascal. Try() stores information in the fields of the FailInfo instance to pass control back to the If statement should an exception occur. It also links itself into the chain of exception handlers. Finally, Try() returns a boolean TRUE, indicating that it is ready to catch an exception and the If clause of the statement is then executed.

In the above example if the call to SetPictureRsrcID() fails we will automatically jump to the portion of the If statement that tests the return value of Try(). However, this time the value returned is FALSE, so we jump to the ELSE clause of the statement and begin executing the exception handling code. If we were successful in retrieving the picture, we call the Success() method of the FailInfo instance.

Unlike Pascal, C++ style exception handling does not automatically propagate the exception to the next exception handler in the chain. When an exception is bracketed with a Try() instead of CatchFailures(), a JMP rather than a JSR is used to arrive at the exception handler, so we never return to MacApp's exception handling code where it can continue by calling Failure() automatically. If we wish to propagate the exception, we must do so explicitly. This is done at the end of the exception handling code by calling the ReSignal() method of the FailInfo instance. What if we don't want to propagate the exception? C++ style exception handling makes this easy. If we don't include the call to ReSignal(), we continue execution with the first statement following the IF statement.

The Need for VOLATILE

We learned before that when CatchFailures() or Try() is called the current state of all registers is saved. If an exception occurs, the registers are restored to their saved state. But what happens if we modified a variable in the bracketed code that was cached by the compiler in a register? Unfortunately we lose the modified value. This becomes a serious problem if we must then reference the variable in the exception handling part of the code. If, for example, the variable was a newly allocated handle that should be freed on exception, we would lose our reference and would not be able to dispose of it. What is needed is a way to ensure that a variable or parameter is not cached in a register.

The concept of a value being volatile was introduced to do just that. Volatile is a hint to the compiler that the variable in question could change and should not be cached in a register. Volatile is a keyword in both ANSI C and C++. However, Apple's C compiler does not have an implementation of volatile that is sufficient for C++. Therefore, CFront ignores the volatile keyword and does not pass it on to the C compiler. To solve the problem, MacApp 3.0 defines a macro for C++ users called VOLATILE (all upper case). The macro is quite simple:

#define VOLATILE(a) ((void) &a)

By taking the address of a variable or parameter we prevent the compiler from caching it in a register. While this approach currently works for CFront and C, a smarter compiler might optimize the statement away and then go ahead and cache the variable in a register. A different compiler could require a different definition of VOLATILE.

The macro is used like this:

pascal void TWindow::IWindow(TDocument* itsDocument,
                        WindowPtr itsWMgrWindow,
                        …
                        Boolean disposeOnFree)
{
    VOLATILE(itsWMgrWindow);
    VOLATILE(disposeOnFree);

    FailInfo fi;
    if (fi.Try())
    {
        …

Do all variables and parameters need to be declared VOLATILE if we are using exception handling? Thankfully no, since we really do want our compilers to optimize our code as much as possible. The rule for declaring a value as volatile is:

  • Any four-byte or smaller local variable or parameter that is modified in the IF clause of an exception handler and used in the ELSE clause must be declared VOLATILE.

Typical examples are Pointers, Handles, Object references, long or short integer counters, etc.

One more comment about the use of volatile. Those of you who have been using Pascal style exception handling in the current and previous versions of MacApp may be wondering why the use of volatile has never been required. The answer is in the types of optimizations the Pascal compiler can make. When a local or nested procedure is defined, as is always the case for Pascal style exception handling, the Pascal compiler is incapable of optimizing any variable or parameter into a register. Therefore no hints from the developer are required!

C++ Style Exception Handling For Pascal

Neither style of exception handling is exclusive to the language it was initially designed for. With a little effort C++ style exception handling is possible with Pascal in MacApp 3.0. What does it look like?:
PROCEDURE TPicture.IPicture(…);
    VAR fi:     FailInfo;

    BEGIN
    …
    IF Try(fi) THEN
        BEGIN
        SELF.SetPictureRsrcID(itsRsrcID, kDontRedraw);
        Success(fi);
        END
    ELSE
        BEGIN
        SELF.Free;
        Failure(fi.error, fi.message);
        END;
    …

Because FailInfo is not a class in Pascal, we must use the global procedures Try(), Success(), and Failure(), passing our local instance of FailInfo as the parameter. Unfortunately Try() is not externalized in UFailure.p. Part of the extra effort required to use C++ style exception handling in Pascal with MacApp 3.0 is adding a declaration for Try():

FUNCTION Try(VAR fi: FailInfo): BOOLEAN; C; EXTERNAL;

The declaration can be added to your UFailure.p if you are willing to modify your MacApp sources. If not, you can add it to your own source where needed.

The other missing component to support C++ style exception handling in Pascal is a solution for volatile values. Because we are no longer using nested procedures as exception handlers, the Pascal compiler may have optimized local variables and parameters into registers for us. However, unlike C++, Pascal has there is no volatile keyword and no macro capability for extending the language as we did with MacApp 3.0. Luckily we can define a small inline procedure that will serve our purpose nicely:

PROCEDURE VOLATILE(p: UNIV Ptr);
inline 588F;    { ADDQ.L #$4,A7 }

As with the above declaration for Try() this declaration can also be added to your UFailure.p interface or to one of your own headers if you prefer not to modify MacApp. The declarations for both Try() and VOLATILE() have been added to UFailure.p in MacApp 3.0.1, so C++ style exception handling will be fully supported in Pascal.

The same rules apply for determining if a value should be declared VOLATILE in Pascal and C++. However the usage model is slightly different:

PROCEDURE TWindow.IWindow(itsDocument: TDocument,
                        itsWMgrWindow: WindowPtr,
                        …
                        disposeOnFree: BOOLEAN);
    VAR fi: FailInfo;

    BEGIN
    VOLATILE(@itsWMgrWindow);
    VOLATILE(@disposeOnFree);

    IF Try(fi) THEN
        BEGIN
        …

This implementation of VOLATILE requires you to take the address of the variable or parameter that you do not wish the compiler to optimize.

Pascal Style Exception Handling in C++

Pascal style exception handling is still useful in some interesting ways with C++. In particular, MacApp 3.0 uses Pascal style exception handling for certain kinds of value-based or stack-based C++ objects.

Iterators are a special class of value-based objects that can iterate over MacApp's dynamic arrays. One nice feature of dynamic arrays is that iterations can be nested. That is, more than one iterator at a time can be installed for a single dynamic array with each iterator at a different stage of iteration. To make this possible, each dynamic array stores a pointer to a circular list of installed iterators. If during iteration an object becomes inserted into the dynamic array, each of the iterators in the list has its index modified accordingly so that it can continue to iterate properly. When an iterator is finished iterating it removes itself from the list of iterators maintained by its dynamic array.

But what happens if a failure occurs during the iteration? Because an iterator is allocated on the stack it ceases to exist when we exit the iterator's enclosing block and clean up the stack. We need to remove the iterator from the list of iterators maintained by the dynamic array; otherwise it is left with a pointer to an iterator that no longer exists. It's clear that we need an exception handler installed during the life of the iterator so that if an exception occurs the iterator can be removed from the dynamic array's list of iterators.

One of the fields of an iterator is an instance of a FailInfo class. Iterators also have a special method called HandleFailure() which encapsulates the behavior required to unlink the iterator from the list of iterators. During the iterator's IMethod, HandleFailure() is installed with CatchFailures() as the exception handler to be called should an exception occur :

void CArrayIterator::IArrayIterator(…)
{
    …
    // Setup the FailInfo to catch any failures
    // while this object is in scope
    // giving control to the HandleFailure method
    CatchFailures( this->fFailInfo,
        (CatchFailuresType) &CArrayIterator::HandleFailure, this);
} // CArrayIterator::IArrayIterator

As described before, CatchFailures() requires two parameters: an instance of a FailInfo class or record and the procedure to call when an exception occurs. Iterators pass the fFailInfo field as the FailInfo instance and the address of the HandleFailure() method as the method to call. Unlike Pascal we are able to pass the address of methods in C++. But why and how are we able to pass this as a normally non existent third parameter?

CatchFailures() is defined with Pascal calling conventions. Because procedures can be nested in Pascal, a hidden parameter, referred to as the static-link in MacApp, is always passed as the last parameter. If the procedure is nested, the hidden parameter is a pointer to the local scope of that procedure so that it has access to local variables and parameters. If the procedure is not nested, the hidden parameter has a value of NULL. Similar to Pascal, C++ always passes a hidden parameter this to methods for access to the class scope. Because the hidden parameter of Pascal and C++ are both passed as the last parameter to the procedure or method, we can replace the pointer to the static link with a pointer to the class scope of the iterator instance. Now when HandleFailure() is called it will be able to access all of the fields and methods of the instance. If the iterator was successful in iterating over the list, it needs to remove itself from the list of iterators maintained by the dynamic array:

CArrayIterator::~CArrayIterator()
{
    if (fDynamicArray)
    {
        // Remove our entry in the failure handling
        // system as we are going out of scope
        // Use this style of success for efficiency.
        fFailInfo.Success();
        …
    }
} // CArrayIterator::~CArrayIterator

This is done by calling success with the iterator's fFailInfo fields in the class destructor. Why do we use a C++ style call to success rather than a Pascal style when the failure handler was installed with CatchFailures? Actually either one can can be used here but the C++ style call to success is turned into an inline for non-debug builds making it slightly faster to execute.

If we fail during iteration, then the iterator's HandleFailure() will be called:

pascal void CArrayIterator::HandleFailure(OSErr,long)
{
    fDynamicArray->fIteratorPtr = this->RemoveFromList();

    // Check if there is a pending free request that
    // couldn't be honored because we were iterating and if
    // so… be free!
    if (fDynamicArray->fFreeRequested && 
            !fDynamicArray->fIteratorPtr)
        fDynamicArray->Free();

    // the error will be resignalled automatically
    // with the Pascal style of failure handler 
} // CArrayIterator::HandleFailure  

It will take care of removing the iterator from the dynamic arrays list of iterators, honor any requests to free the list which could not be serviced during iteration, and, since we wish to continue propagating the exception to the next exception handler, do nothing, remembering that exception handlers installed with CatchFailures() always resignal an exception automatically.

FailInfo Fields

Part of understanding how exception handling works in MacApp is understanding the fields of the FailInfo record. In C++ FailInfo is defined as a class but is bit-wise compatible with the definition in Pascal:
class FailInfo {
public:
    long        regs[12];   // The saved registers
    short       flags;      // 0 for CatchFailures, 1 for Try
    short       error;      // Error condition passed to Failure
    long        message;    // Failure message
    long        failA6;     // Static-Link passed to Pascal handler
    long        failPC;     // Address of failure handler routine
    FailInfo*   nextInfo;   // Next handler in the chain 
#if qDebug
    long        whoPC;      // Address of the caller
    short       installed;  // Linked into the chain?
#endif
}

When an exception handler is installed with CatchFailures() or Try(), most of the registers, specifically A2-A7 and D2-D7, are saved in regs. If an exception occurs, DoFailures() uses regs to restore the registers to their previous state. The flags field is used to determine how the exception handler was installed. If flags has a value of 0, then the exception handler was installed with CatchFailures() and will need to be called as a procedure. The address of the procedure to be called is stored in failPC, and the link to its local scope is stored in failA6. If the value is 1, then the exception handler was installed with a Try() and DoFailure() will JMP rather than JSR to the address stored in failPC. The failA6 field is unused when using Try(). The error and message fields are set to the value of the parameters passed to Failure() when an exception occurs. These will be passed on to the next exception handler in the chain, pointed to by nextInfo, if the exception handler was installed with CatchFailures() or if the exception is explicitly resignalled.

The last two fields are only available for debug builds of MacApp. The whoPC field points to the instruction following the call to CatchFailures() or Try(). It is used to determine the name of the method that caught the exception. For exception handlers installed with Try(), failPC and whoPC have the same value.

One of the common mistakes made when wrapping code that could cause an exception is forgetting to call Success(). Forgetting to call success can lead to some serious problems. Because the state of all registers including the PC are saved in a FailInfo class, an exception handler that is not removed from the chain by calling Success() could jump to a code segment that has since been unloaded. Debug builds of MacApp warn you the next time you call Success() that you have either too few or too many calls to Success. However, it is sometimes difficult to determine where.

The last field, installed, is available only to C++ users and is used to determine as early as possible that a call to success was forgotten. It is set to TRUE when the exception handler is linked into the chain of exception handlers with CatchFailures() or Try(). If an exception occurs or Success() is called, installed is set to FALSE again. The C++ version of FailInfo defines a destructor for debug builds of MacApp that checks the value of installed. Because the FailInfo destructor is only called if no exception occurred, a value of TRUE indicates that we forgot to call Success(), and we are informed immediately.

FailInfo Methods

In addition to the fields that are common between the Pascal and C++ definitions of FailInfo, C++ adds some useful methods:
class FailInfo {
public:
    inline FailInfo::FailInfo()
    inline Boolean FailInfo::Try(> {return ::Try(*this);}
    inline void FailInfo::ReSignal()
                            {::Failure(error, message);}
#if qDebug
    inline FailInfo::~FailInfo();
    inline void FailInfo::Success() {::Success(*this);}
#else
    inline void FailInfo::Success() {gTopHandler = nextInfo;}
#endif
}

For non-debug builds of MacApp all the methods are defined as inline, so the resulting code looks very much like what you get when doing C++ style exception handling in Pascal. The only difference is the Success() method. Debug builds of MacApp continue to call the global procedure Success() because it will perform some useful debug checks. Non-debug builds optimize Success() so that it only does the required work of unlinking the exception handler from the chain of exception handlers.

Conclusion

Exception handling is an important part of MacApp and is the key to developing applications that respond in a consistent manner under varying conditions. With an understanding of the mechanics of exception handling we are better able to discuss how exception handling can be used in your applications. In the next article I will define the ground rules that are essential to understanding when and how to integrate exception handling. I will also work through some typical examples in MacApp, look at ways of reducing the number of exception handlers that might be required, and try to answer some of the more esoteric questions developers have about exception handling.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Cocktail 8.4 - General maintenance and o...
Cocktail is a general purpose utility for OS X that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
PDFKey Pro 4.3 - Edit and print password...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Kodi 15.0.beta1 - Powerful media center...
Kodi (was XBMC) is an award-winning free and open-source (GPL) software media player and entertainment hub that can be installed on Linux, OS X, Windows, iOS, and Android, featuring a 10-foot user... Read more
DiskCatalogMaker 6.4.12 - Catalog your d...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast. Finder-like intuitive look and feel. Super-fast search algorithm. Can compress catalog data... Read more
Macs Fan Control 1.3.0.0 - Monitor and c...
Macs Fan Control allows you to monitor and control almost any aspect of your computer's fans, with support for controlling fan speed, temperature sensors pane, menu-bar icon, and autostart with... Read more
Lyn 1.5.11 - Lightweight image browser a...
Lyn is a lightweight and fast image browser and viewer designed for photographers, graphic artists and Web designers. Featuring an extremely versatile and aesthetically pleasing interface, it... Read more
NeoOffice 2014.11 - Mac-tailored, OpenOf...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
LaunchBar 6.4 - Powerful file/URL/email...
LaunchBar is an award-winning productivity utility that offers an amazingly intuitive and efficient way to search and access any kind of information stored on your computer or on the Web. It provides... Read more
Remotix 3.1.4 - Access all your computer...
Remotix is a fast and powerful application to easily access multiple Macs (and PCs) from your own Mac. Features Complete Apple Screen Sharing support - including Mac OS X login, clipboard... Read more
DesktopLyrics 2.6.6 - Displays current i...
DesktopLyrics is an application that displays the lyrics of the song currently playing in "iTunes" right on your desktop. The lyrics for the song have to be set in iTunes; DesktopLyrics does nothing... Read more

What the Apple Watch Gets Right, and Wha...
| Read more »
Celebrate PAC-MAN's 35th Birthday W...
BANDAI NAMCO Entertainment America is celebrating PAC-MAN's 35th anniversary by releasing updates for PAC-MAN and PAC-MAN Lite for iOS. [Read more] | Read more »
Strike Wing Episode 2 has Landed on the...
Strike Wing: Raptor Rising is an exciting space combat simulator by Crescent Moon Games, which was recently updated to continue the story with Episode 2. [Read more] | Read more »
This Week at 148Apps: May 18-22, 2015
May Days at 148Apps How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you're looking for. The ones we love become Editor’s Choice, standing out above the... | Read more »
Biz Builder Delux (Games)
Biz Builder Delux 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Ah, there's nothing like the rhythmic bustle of a burgeoning business burg... especially when you're the one building it... | Read more »
Auroch Digital is Bringing Back Games Wo...
| Read more »
Blades of Brim is a New Endless Runner f...
SYBO Games, the minds behind the ever-popular Subway Surfers, have announced their latest project: Blades of Brim. [Read more] | Read more »
Carbo - Handwriting in the Digital Age...
Carbo - Handwriting in the Digital Age 1.0 Device: iOS Universal Category: Productivity Price: $3.99, Version: 1.0 (iTunes) Description: | Read more »
Draggy Dead (Games)
Draggy Dead 1.1 Device: iOS Universal Category: Games Price: $.99, Version: 1.1 (iTunes) Description: Ditch your dead end job and take up a rewarding career in Grave Robbing today!Guide the recently deceased to a fun filled life of... | Read more »
Bad Dinos (Games)
Bad Dinos 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

New 13-inch 2.9GHz Retina MacBook Pro on sale...
B&H Photo has the 13″ 2.9GHz/512GB Retina MacBook Pro on sale for $1699.99 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price for this model from... Read more
12-inch MacBook stock status for Monday, May...
The new 12″ Retina MacBooks are still on backorder at The Apple Store with a 3-5 week waiting period. However, a few models are in stock today at Apple resellers. Stock is limited, so act now if you’... Read more
New 27-inch 3.3GHz 5K iMac in stock with free...
Adorama has the new 27″ 3.3GHz 5K iMac in stock today for $1999 including free shipping plus NY & NJ sales tax only. Adorama will include a free copy of Apple’s 3-year AppleCare Protection Plan. Read more
Memorial Day Weekend Sale: New 27-inch 3.3GHz...
Best Buy has the new 27″ 3.3GHz 5K iMac on sale for $1899.99 this weekend. Choose free shipping or free local store pickup (if available). Sale price for online orders only, in-store prices may vary... Read more
OtterBox Maximizes Portability, Productivity...
From the kitchen recipe book to the boarsroom presentation, the OtterBox Agility Tablet System turns tablets into one of the most versatile pieces of handheld technology available. Available now, the... Read more
Launch of New Car App Gallery and Open Develo...
Automatic, a company on a mission to bring the power of the Internet into every car, has announced the launch of the Automatic App Gallery, an app store for nearly every car or truck on the road... Read more
Memorial Day Weekend Sale: 13-inch 1.6GHz Mac...
Best Buy has the new 13″ 1.6GHz/128GB MacBook Air on sale for $849 on their online store this weekend. Choose free shipping or free local store pickup (if available). Sale price for online orders... Read more
Memorial Day Weekend Sale: 27-inch 3.5GHz 5K...
Best Buy has the 27″ 3.5GHz 5K iMac on sale for $2099.99 this weekend. Choose free shipping or free local store pickup (if available). Sale price for online orders only, in-store prices may vary.... Read more
Sale! 16GB iPad mini 3 for $349, save $50
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $349 including free shipping plus NY sales tax only. Their price is $50 off MSRP, and it’s the lowest price available for this model. Read more
Price drop on 2014 15-inch Retina MacBook Pro...
B&H Photo has dropped prices on 2014 15″ Retina MacBook Pros by $200. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799.99 save $200 - 15″ 2.5GHz... Read more

Jobs Board

Architect / Senior Software Engineer, *Apple...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
*Apple* Pay Support Readiness Project Manage...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
Hardware Design Validation Engineer - *Apple...
**Job Summary** The Apple Watch team is looking for a Hardware Design Validation Engineer. This person will be part of the Apple Watch hardware team with Read more
Sr. Payment Program Manager, *Apple* Pay -...
**Job Summary** Apple Pay is an exciting environment and a…devices in a simple, private and secure way. The Apple Pay Team is looking for an experienced Senior Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.