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);

    CatchFailures(fi, HandleFailure);
    fDataHandle := GetPicture(fRsrcID);

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: CArrayIterator::IArrayIterator(…)
Failure caught by: TODOCCOMMAND.DOIT

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);
        GOTO 1;

    CatchFailures(fi, HandleFailure);
    fDataHandle := GetPicture(fRsrcID);

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);
    else    // Recover

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)

    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;

    IF Try(fi) THEN
        SELF.SetPictureRsrcID(itsRsrcID, kDontRedraw);
        Failure(fi.error, fi.message);

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():


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:

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;


    IF Try(fi) THEN

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:

    if (fDynamicArray)
        // Remove our entry in the failure handling
        // system as we are going out of scope
        // Use this style of success for efficiency.
} // 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 && 

    // 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 {
    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?

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 {
    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);}
    inline void FailInfo::Success() {gTopHandler = nextInfo;}

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.


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

FotoMagico 5.3 - Powerful slideshow crea...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more
Acorn 5.6.1 - Bitmap image editor.
Acorn is a new image editor built with one goal in mind - simplicity. Fast, easy, and fluid, Acorn provides the options you'll need without any overhead. Acorn feels right, and won't drain your bank... Read more
Dash 3.4.3 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
Microsoft Remote Desktop 8.0.37 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
Macs Fan Control - 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
MacFamilyTree 8.1.3 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more
Boom 2 1.5.2 - $14.99
Boom 2 is a system-wide volume booster and equalizer app that is designed especially for OS X 10.10 Yosemite. It comes with a smart interface, self-calibrates itself according to your Mac, offers... Read more
Macs Fan Control - 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
Boom 2 1.5.2 - $14.99
Boom 2 is a system-wide volume booster and equalizer app that is designed especially for OS X 10.10 Yosemite. It comes with a smart interface, self-calibrates itself according to your Mac, offers... Read more
MacFamilyTree 8.1.3 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more

Stickman Surfer rides in with the tide t...
Stickson is back and this time he's taken up yet another extreme sport - surfing. Stickman Surfer is out this Thursday on both iOS and Android, so if you've been following the other Stickman adventures, you might be interested in picking this one... | Read more »
Z-Exemplar (Games)
Z-Exemplar 1.4 Device: iOS Universal Category: Games Price: $3.99, Version: 1.4 (iTunes) Description: | Read more »
5 dastardly difficult roguelikes like th...
Edmund McMillen's popular roguelike creation The Binding of Isaac: Rebirth has finally crawled onto mobile devices. It's a grotesque dual-stick shooter that tosses you into an endless, procedurally generated basement as you, the pitiable Isaac,... | Read more »
Last week on PocketGamer
Welcome to a weekly feature looking back on the past seven days of coverage on our sister website, PocketGamer. It’s taken a while for 2017 to really get going, at least when it comes to the world of portable gaming. Thank goodness, then, for... | Read more »
ROME: Total War - Barbarian Invasion set...
To the delight of mobile strategy fans, Feral Interactive released ROME: Total War just a few months ago. Now the game's expansion, Barbarian Invasion is marching onto iPads as a standalone release. [Read more] | Read more »
Yuri (Games)
Yuri 1.0 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: It's night. Yuri opens his eyes. He wakes up in a strange forest.The small, courageous explorer rides on his bed on casters in this... | Read more »
Space schmup Xenoraid launches on the Ap...
10Tons Xenoraid is out today on the App Store, bringing some high-speed space action to your mobile gadgets just in time for the weekend. The company's last premium title, another sci-fi game titled Neon Chrome, did quite well for itself, so... | Read more »
Star Wars: Force Arena Beginner's G...
Star Wars: Force Arena joined the populous ranks of Star Wars games on mobile today. It's a two-lane MOBA starring many familiar faces from George Lucas's famed sci-fi franchise. As with most games of this nature, Force Arena can be a little obtuse... | Read more »
Mysterium: The Board Game (Games)
Mysterium: The Board Game 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: The official adaptation of the famous board game Mysterium! | Read more »
Sonny (Games)
Sonny 1.0.4 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.4 (iTunes) Description: Reimagined for iOS, cult-hit RPG Sonny brings challenging turn-based combat that requires strategy and mastery of each new skill to... | Read more »

Price Scanner via

15-inch 2.2GHz Retina MacBook Pro on sale for...
Amazon has 2015 15″ 2.2GHz Retina MacBook Pros (MJLQ2LL/A) available for $1799.99 including free shipping. Apple charges $1999 for this model, so Amazon’s price is represents a $200 savings. Read more
Back in stock: Apple refurbished 13-inch Reti...
Apple has Certified Refurbished 2015 13″ Retina MacBook Pros available for up to $360 off original MSRP, starting at $1099. An Apple one-year warranty is included with each model, and shipping is... Read more
CalcTape for macOS 1.2 Adding Machine App for...
schoettler Software has announced CalcTape 1.2, an update to their desktop calculator for macOS. When it comes to adding long columns of numbers, doing complex calculations or playing around with... Read more
New MacBooks And MacBook Pros WIth Kaby Lake...
Digitimes’ Joseph Tsai cites a Chinese-language Economic Daily News (EDN) report that unnamed market watchers are predicting Apple MacBook shipments to grow 10 percent in 2017, and projecting 15... Read more
New 2016 13-inch MacBook Pros on sale for up...
B&H Photo has the new 2016 13″ MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.9GHz/512GB Touch Bar MacBook Pro... Read more
New 15-inch Touch Bar MacBook Pros in stock a...
B&H Photo has the new 2016 15″ Apple Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.7GHz Touch Bar... Read more
Opera Announces Neon Concept Browser For Mac
Opera is inviting users to get a glimpse of what Opera for computers could become with its Opera Neon browser concept. Each Opera Neon feature is described as “an alternate reality” for the Opera... Read more
Tellini Releases TabView 3.0 Missing Tool fo...
Tellini has announced the release of TabView 3.0. TabView has been the first macOS viewer for PowerTab tablatures. PowerTab is a well-known and widely adopted tablature editor for Windows systems and... Read more
13-inch 1.6GHz/128GB MacBook Air on sale for... has the 1.6GHz/128GB 13″ MacBook Air on sale for $130 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (MMGF2LL/A): $869.99 $130 off MSRP Their price is the lowest... Read more
12-inch 32GB Space Gray iPad Pro on sale for...
B&H Photo has 12″ Space Gray 32GB WiFi Apple iPad Pros on sale for $55 off MSRP including free shipping. B&H charges sales tax in NY only: - 12″ Space Gray 32GB WiFi iPad Pro: $744.44 $55 off... Read more

Jobs Board

*Apple* Retail - Multiple Positions (Multi-L...
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 - 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* & PC Desktop Support Technician...
Apple & PC Desktop Support Technician job in Stamford, CT We have immediate job openings for several Desktop Support Technicians with one of our most well-known Read more
*Apple* macOS Systems Integration Administra...
…most exceptional support available in the industry. SCI is seeking an Junior Apple macOS systems integration administrator that will be responsible for providing Read more
*Apple* Premier Retailer - Service Technicia...
DescriptionSimply Mac is the largest premier retailer for Apple products and solutions. At Simply Mac we are all Apple , all the time. Same products. Same prices. Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.