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

Spotify 1.0.44.100. - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Microsoft OneNote 15.29 - Free digital n...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
WALTR 2 2.0.8 - $39.95
WALTR 2 helps you wirelessly drag-and-drop any music, ringtones, videos, PDF, and ePub files onto your iPhone, iPad, or iPod without iTunes. It is the second major version of Softorino's critically-... Read more
Dropbox 16.3.27 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
EtreCheck 3.1.5 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
Carbon Copy Cloner 4.1.12 - Easy-to-use...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
VueScan 9.5.62 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
SpamSieve 2.9.27 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
Fantastical 2.3.2 - Create calendar even...
Fantastical 2 is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event... Read more
PCalc 4.4.4 - Full-featured scientific c...
PCalc is a full-featured, scriptable scientific calculator with support for hexadecimal, octal, and binary calculations, as well as an RPN mode, programmable functions, and an extensive set of unit... Read more

Latest Forum Discussions

See All

Track Santa with these three festive app...
Christmas is fast approaching and that means it's time to prepare for Santa's yearly pilgrimage around the globe. Christmas Eve is an exciting time as parents help their kids get ready to welcome Santa. You've got the cookies and milk all planned... | Read more »
Galaxy on Fire 3 and four other fantasti...
Galaxy on Fire 3 - Manticore brings the series back for another round of daring space battles. It's familiar territory for folks who are familiar with the franchise. If you've beaten the game and are looking to broaden your horizons, might we... | Read more »
The best apps for your holiday gift exch...
What's that, you say? You still haven't started your holiday shopping? Don't beat yourself up over it -- a lot of people have been putting it off, too. It's become easier and easier to procrastinate gift shopping thanks to a number of apps that... | Read more »
Toca Hair Salon 3 (Education)
Toca Hair Salon 3 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Winter comes to Darkwood as Seekers Note...
MyTona, based in the chilly Siberian city of Yakutsk, has brought a little festive fun to its hidden object game Seekers Notes: Hidden Mystery. The Christmas update introduces some new inhabitants to players, and with them a chance to win plenty of... | Read more »
Bully: Anniversary Edition (Games)
Bully: Anniversary Edition 1.03.1 Device: iOS Universal Category: Games Price: $6.99, Version: 1.03.1 (iTunes) Description: *** PLEASE NOTE: This game is officially supported on the following devices: iPhone 5 and newer, iPod Touch... | Read more »
PINE GROVE (Games)
PINE GROVE 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: A pine grove where there are no footsteps of people due to continuous missing cases. The case is still unsolved and nothing has... | Read more »
Niantic teases new Pokémon announcement...
After rumors started swirling yesterday, it turns out there is an official Pokémon GO update on its way. We’ll find out what’s in store for us and our growing Pokémon collections tomorrow during the Starbucks event, but Niantic will be revealing... | Read more »
3 reasons why Nicki Minaj: The Empire is...
Nicki Minaj is as business-savvy as she is musically talented and she’s proved that by launching her own game. Designed by Glu, purveyors of other fine celebrity games like cult favorite Kim Kardashian: Hollywood, Nicki Minaj: The Empire launched... | Read more »
Clash of Clans is getting its own animat...
Riding on its unending wave of fame and success, Clash of Clans is getting an animated web series based on its Clash-A-Rama animated shorts.As opposed to the current shorts' 60 second run time, the new and improved Clash-A-Rama will be comprised of... | Read more »

Price Scanner via MacPrices.net

Never Settle for Low Performing Wifi With iOS...
AppYogi Software has announced the release of WiFi Signal Strength Status App 1.0, the company’s new utility developed exclusively for macOS. WiFi Signal Strength Status App features a unique, single... Read more
New 2016 13-inch Touch Bar MacBook Pros in st...
B&H Photo has stock of new 2016 Apple 13″ Touch Bar MacBook Pro models, each including free shipping plus NY sales tax only: - 13″ 2.9GHz/512GB Touch Bar MacBook Pro Space Gray: $1999 - 13″ 2.... Read more
New 2016 15″ Touch Bar MacBook Pros in stock...
B&H Photo has new 2016 Apple 15″ Touch Bar MacBook Pro models in stock today including free shipping plus NY sales tax only: - 15″ 2.7GHz Touch Bar MacBook Pro Space Gray: $2799 - 15″ 2.7GHz... Read more
DietSensor App Targeting Diabetes and Obesity...
DietSensor, Inc., a developer of smart food and nutrition applications designed to fight diabetes and obesity and help improve overall fitness, has announced the launch of its DietSensor app for... Read more
Holiday 2016 13-inch 2.0GHz MacBook Pro sales...
B&H has the non-Touch Bar 13″ MacBook Pros in stock today for $50-$100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.0GHz MacBook Pro Space Gray (MLL42LL/A): $1449 $... Read more
Holiday sale: Apple TVs for $51-$40 off MSRP,...
Best Buy has dropped their price on the 64GB Apple TV to $159.99 including free shipping. That’s $40 off MSRP. 32GB Apple TVs are on sale right now for $98 on Sams Club’s online store. That’s $51 off... Read more
12-inch Retina MacBooks, Apple refurbished, n...
Apple has restocked a full line of Certified Refurbished 2016 12″ Retina MacBooks, now available for $200-$260 off MSRP. Refurbished 2015 models are available starting at $929. Apple will include a... Read more
Holiday sale: 12-inch Retina MacBook for $100...
B&H has 12″ Retina MacBooks on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199 $100... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $849 $... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
US- *Apple* Store Leader Program - Apple (Un...
…Summary Learn and grow as you explore the art of leadership at the Apple Store. You'll master our retail business inside and out through training, hands-on Read more
Automotive Detailer - *Apple* Used Autos -...
We are currently conductinginterviews and will be accepting applications for a part-time detailer. Apple Used Autos is a great place to work andstart a career. We Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- Trumbul...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.