TweetFollow Us on Twitter

The Road to Code: Quit Bugging Me

Volume Number: 25 (2009)
Issue Number: 02
Column Tag: The Road to Code

The Road to Code: Quit Bugging Me

Debugging on Mac OS X

by Dave Dribin

The Perfect Story

You've been a faithful reader of The Road to Code. You've typed in every code example to gain complete understanding. If you had problems getting something working, you could always download the source code from the MacTech web site. But now, you're off on your own. You've started writing your own applications, and inevitably, something goes wrong. Your application doesn't work as you expect it. Or it crashes, losing all your hard-entered data. How do you figure out what's going wrong?

The process of fixing an application that does not work correctly is called debugging. The term debugging in the context of computer software is often credited to an early computer scientist named Grace Hopper. As the legend goes, she was working on the Mark II system at Harvard, investigating a glitch in the system. The problem ended up being a moth stuck in one of the relays, and she dubbed this the "first actual case of bug being found". From then on, whenever a computer system has not worked, it is blamed on bugs. Thus, removing bugs in a computer program is called debugging.

That's a fine and dandy story, but how do you actually debug a program? It's not as if you will usually find real moths stuck inside your computer to eradicate. Let's go over some techniques that you can use to help you debug your own code.

Simple Logging

One of the simplest debugging techniques is to use logging. Say some variable is not being set correctly, and you do not know why. You can begin tracking down the problem by inserting NSLog statements to print its value out to the console. You can even use NSLog in a GUI application and then view the output in the Xcode console. This kind of debugging, while primitive, is surprisingly effective. It's also one of the easiest to implement, since printing to the console is one of the first things you learn how to do.

Sometimes this kind of debugging is called printf debugging, because in straight C you use the printf function instead of NSLog. Using NSLog in Objective-C has some nice advantages, but the main one is the %@ format pattern to print objects. You can use the %@ format string to print any Objective-C object. For example, to print an NSString variable:

    NSString * name = @"Joe";
    NSLog(@"name: %@", name);

You've seen code like this before. The %@ in the format string gets substituted with the string value:

2008-12-07 22:49:09.356 Rectangles[60874:10b] name: Joe

Along with the message you pass as its arguments, NSLog prints the application name and a timestamp. We've seen how you can use other format patterns, such as %d to print integers and %f to print floating point numbers. The %@ formatter works on any class, not just NSString though. Here's how you could print an NSNumber instance:

    NSNumber * number = [NSNumber numberWithInt:42];
    NSLog(@"number: %@", number);

The output would look like this:

number: 42

I'm omitting the timestamp and application name from now on, to keep the output succinct, but there's nothing too surprising going on here. You get useful output on a surprising number of classes included in Foundation and AppKit. For example, logging an NSArray instance displays the contents of the array:

    NSArray * array =
       [NSArray arrayWithObjects:@"Jack", @"Jane", nil];
    NSLog(@"array: %@", array);

The output would look like this:

array: (
    Jack,
    Jane
)

You can even use %@ on your own objects; however, it doesn't always provide useful information. Let's use the Rectangles application from the October 2008 issue, as an example. You can get it from the MacTech FTP site, if you need to. Here's how you could log one of our Rectangle objects:

    Rectangle * rectangle =
        [[Rectangle alloc]   initWithLeftX:0
                                 bottomY:0
                                  rightX:15
                                    topY:10];
    NSLog(@"rectangle: %@", rectangle);

And here's what it looks like by default:

rectangle: <Rectangle: 0x104fba0>

Hrm... not very useful. It's printing out the pointer value of the object. Luckily, we can customize this output. In order to turn an object into a string, NSLog uses the description method defined on NSObject. The default implementation prints the class name and the pointer value of self, and it would look something like this:

- (NSString *)description
{
    NSString * description =
        [NSString stringWithFormat:@"<%@: %p>", [self className], self];
    return description;
}

It's using the className method, also defined on NSObject, to get the name of the class as a string. The %p format specifier prints out pointer values. The output is the hexadecimal number of the memory address of the pointer.

By overriding description in our Rectangle class, we can give it more meaningful output. As a refresher, Listing 1 shows the interface for the Rectangle class.

Listing 1: Rectangle.h header file

#import <Foundation/Foundation.h>
@interface Rectangle : NSObject <NSCoding>
{
    float _leftX;
    float _bottomY;
    float _width;
    float _height;
}
@property float leftX;
@property float bottomY;
@property float width;
@property float height;
@property (readonly) float area;
@property (readonly) float perimeter;
- (id) initWithLeftX:(float)leftX
            bottomY:(float)bottomY
             rightX:(float)rightX
               topY:(float)topY;
@end

A useful implementation of description would output the leftX, bottomY, width, and height:

- (NSString *)description
{
    NSString * description =
        [NSString stringWithFormat:
         @"<%@: (%.1f, %.1f) %.1f x %.1f>",
         [self className],
         _leftX, _bottomY, _width, _height];
    return description;
}

Now, when we log our rectangle variable above, it would look like this:

rectangle: <Rectangle: (0.0, 0.0) 15.0 x 10.0>

Ah! Much better. We can now use logging to dump our rectangles out to the console.

There are, of course, downsides to using logging for debugging. If you need to view a large number of variables or watch a variable change from line to line, you'll need to insert lots of logging statements. This is tedious and takes time. You also may accidentally leave your debug logging statements inside a shipping application. This can clutter up the user's console and even affect the performance of your application, so it is not a good idea to have NSLog statements in a released application. Don't fret. There's something better called a debugger.

Xcode Debugger

A debugger is an application whose purpose is to help debug another application. The main feature of a debugger is the ability to set breakpoints. Breakpoints allow you to stop the execution of a running application and investigate the state of the application. You can typically examine any local variables, instance variables, and global variables from within a debugger.

Xcode comes with an integrated debugger, meaning that you can use Xcode to set breakpoints. The simplest way to explain how it works is to provide an example. Take this code that is the constructor for the Rectangle class:

- (id) initWithLeftX:(float)leftX
            bottomY:(float)bottomY
             rightX:(float)rightX
               topY:(float)topY
{
    self = [super init];
    if (self == nil)
        return nil;
    
    _leftX = leftX;
    _bottomY = bottomY;
    _width = rightX - leftX;
    _height = topY - bottomY;
    
    return self;
}

Say we want to see if the rectangle is created properly. You simply click on the left margin with the line numbers, and a blue arrow is added to indicate that you added a breakpoint, as in Figure 1.


Figure 1: Setting a breakpoint in Xcode

To trigger the breakpoint, we first need to run our application with the debugger instead of running it normally. You do this by choosing the Build > Build and Debug menu, or Command-Y, instead of the usual Build > Build and Run menu, or Command-R. This will launch your application, but whenever code that has a breakpoint set is executed, the program stops execution. In order to trigger our example breakpoint, you need to hit the Add button in the user interface, which ends up creating a new rectangle.

When you do this, the debugger will stop your program, and Xcode will change the main editor interface to show you that you have stopped at a breakpoint, as shown in Figure 2. You can see that it adds a red arrow in the left margin and it highlights the line that the red arrow is on in blue. This is done to clearly indicate where the debugger has halted your application.Debugger integration within the standard editing window is new to Xcode 3. There is also a separate debugging window, which contains more debugging information. You can view this window by choosing the Run > Debugger menu, which looks like Figure 3.


Figure 2: Xcode stopped at a breakpoint


Figure 3: Xcode debugger window

While your program is halted, you can poke around and investigate its state. The lower pane of the debugger window is similar to the main editor window in that it shows you your code, along with the red arrow and blue highlight to indicate where you application stopped. The upper left pane of the debugger window shows the method call stack, or stack trace. This shows all method calls that lead you to this point, all the way back to main function that started the application.

The upper right pane of the debugger window allows you to examine the value of any variable. Variables that contain other variables, such as structures or objects, have a little disclosure triangle. Clicking on the triangle displays the containing variables. For example, clicking on the triangle of the self variable allows us to examine the instance variables, as shown in Figure 4. As you can see, all instance variables are set to zero initially.


Figure 4: Examining variables

Examining variables is extremely helpful when trying to figure out how your application is misbehaving, but there is a lot more you can do with a debugger. Most likely, you are going to want to start your application up again. There are two ways to resume execution of your program: continuing and stepping. Continuing starts the application back up again, and it will resume as if nothing happened.

Stepping allows you to continue execution temporarily and execute the statements of your program one at a time. By stepping through your program, you can watch how each statement modifies variables. Say we step over the four statements that assign the instance variables. The debugger window would now look like Figure 5.


Figure 5: Stepping over statements

You will notice that the red arrow and blue highlight move as each statement is executed. Also the variable examination pane highlights variables that have changed in red. Thus, the _height instance variable is red because we just assigned to it. You can keep stepping as long as you would like and watch your application execute in slow motion.

There are actually two kinds of stepping: step into and step over. Both continue execution temporarily, but the difference is how the debugger handles method and function calls. Using "step into" the debugger will follow execution into method and function calls and stop at the first statement inside the called method. "Step over" will not follow execution into method and functions calls, and instead will stop on the next line of the current method. If the statement is not a method or function call, then "step into" and "step over" are equivalent.

The toolbar of the debugger window has buttons labeled Continue, Step Over, and Step Into so you can easily restart your application using one of these commands. It's worth noting that you can only step into your own code. Any code that is part of the system frameworks cannot be stepped into.

The upper left pane that shows the method call stack allows you to "back up" the method call chain and view the state of each method, too. By default, the top of the stack is selected. For example, if I click on the second method in the stack, -[MyDocument addRectangle:], the debug window would change to look like Figure 6. Again, you can only select method calls that are in your code. You cannot select methods that are part of the system frameworks, and they are grayed out.


Figure 6: Selected methods in the call stack

The source pane and the variable pane update to the new method when you click on one. Thus, the variable arguments and locals shown in Figure 6 are for the addRectangle: method.

Debugger Console

There's another important part of Xcode's debugger called the debugger console. This is the same console where logging output usually goes, but with the debugger active, it's turned into a command line interface for the debugger.

Xcode's debugger is built around a debugger called gdb, the GNU debugger. gdb is traditionally run from the command line to debug C and C++ programs. Xcode wraps most of gdb's functionality with an easy to use GUI, but the console allows you to enter commands directly to gdb. The print command, for example, prints the value of a variable. You can use this instead of the variable pane in the GUI to examine variables. You can examine the rightX local variable from the console like this:

(gdb) print rightX
$4 = 15

The print command only works on primitive types, though. If you want to examine Objective-C objects, you need to use the print-object command. It uses the same description method that NSLog uses to get the string value of an object, so if we used this on self at the end of the Rectangle constructor, the output would look like this:

(gdb) print-object self
<Rectangle: (0.0, 0.0) 15.0 x 10.0>

You can also use po as a shortcut for print-object:

(gdb) po self
<Rectangle: (0.0, 0.0) 15.0 x 10.0>

The arguments to the print and po commands are not limited to printing variables. You can traverse structures and even call Objective-C methods. To call methods, you use the standard square bracket syntax you normally use. Here's how you would print the class name of self:

(gdb) po [self className]
Rectangle

Note that the debugger does not understand property dot notation. You have to use the square bracket syntax:

(gdb) print self.area
There is no member named area.
(gdb) print [self area]
$6 = 150

Generally print is smart enough to figure out the type to print out, but sometimes you need to give it a hint. If you need to do this, you can use standard C cast syntax to force the value to be a certain type:

(gdb) print (int)[self area]
$7 = 150

The command line is powerful, yet complex. Everything available in the Xcode debugger GUI is available from the gdb console. For example, the commands that correspond to the Continue, Step Over, and Step Into of the GUI are continue, next, and step, respectively.

Breakpoint Actions

One use for gdb commands is to assign actions to breakpoints. Instead of breakpoints stopping the program and not continuing right away, you can add actions to breakpoints. These actions are executed automatically when the breakpoint is triggered. Actions can be gdb commands, log statements, or even AppleScripts.

Xcode has some pre-configured breakpoint actions that you can use when setting a breakpoint. The easiest way to access these is to right click (or Control click) in the left margin of the source editor, and choose Built-in Breakpoints from the contextual menu, as shown in Figure 7.


Figure 7: Built-in Breakpoints

Let's choose Print self and auto-continue to see how it works. Now, when we run our program and cause the breakpoint to trigger, it will log the description of the Rectangle and continue. This is just like adding an NSLog statement, except you do not have to modify your code!

Let's see how this works behind the scenes. Right click on the blue breakpoint arrow in the left margin and choose Edit Breakpoint from the contextual menu. This will bring up the Breakpoints window as shown in Figure 8. Alternatively, you can access this window from the Breakpoints toolbar item or the Run > Show > Breakpoints menu.


Figure 8: Breakpoint with an action

This window shows that the po self debugger command is automatically executed when the breakpoint is hit. Also, the rightmost column is checked, meaning the application is automatically continued. This combination is how you can add logging statements without modifying the code. Again, you can use any gdb command you can type at the console as an action, so breakpoint actions are very powerful.

Debugging Crashes

While breakpoints are a great way to track down bugs, sometimes your application will unexpectedly crash, and you don't know where to start looking. The debugger can help in these cases, too. Crashes can happen for many reasons, but one of the most common is dereferencing a NULL pointer. In order to demonstrate this point, I'm going to make the program crash by inserting a bug.

- (IBAction)addRectange:(id)sender
{
    // Dereference a NULL pointer
    int * pointer = NULL;
    *pointer = 0;
    Rectangle * rectangle =
        [[Rectangle alloc]   initWithLeftX:0
                                 bottomY:0
                                  rightX:15
                                    topY:10];
    
    [_rectangles addObject:rectangle];
    
    // Update the UI
    [_tableView reloadData];
    [self updateTotalAreaAndPerimeter];
}

The second line in the method will cause the application to crash when executed. To trigger this bug, all you have to do is click on the Add button in the GUI. If you try this, you'll notice that Xcode will catch the crash and automatically attach the debugger. The debugger will then highlight the exact line where the crash occurred, with the red arrow and blue highlight, as shown in Figure 9. You can now examine the state of your application to figure out why the crash occurred. In this case, it's obvious: pointer is 0x0, or NULL. However, it may not be obvious in a real crash. The debugger gives you a chance to investigate what caused the crash.


Figure 9: Xcode debugger catching a crash

The debugger will only get attached to a crashing program when running within Xcode. If a program crashes outside of Xcode, you will get a standard dialog, as shown in Figure 10.


Figure 10: Application crash dialog

There's not much information here to help you debug. However, ever time any application crashes, Mac OS X saves what's called a crash log. Crash logs contain information that may help determine why an application crashed, and they are stored in this directory:

~/Library/Logs/CrashReporter/

There's one text file per crash, and if you open up one of these files, you'll see the full crash log. The most useful part of the crash log is what's known as a stack trace. This is similar to the upper left pane of the debugger, in that it shows you the methods called in the current stack before the crash occured. The first line of the crash log (which I've edited for brevity) will look something like this:

Thread 0 Crashed:
0  [...] -[MyDocument addRectange:] + 29 (MyDocument.m:64)
1  [...] -[NSApplication sendAction:to:from:] + 112
[...]
11 [...] 0x00002679 main + 30 (main.m:14)
12 [...] start + 54

It tells us exactly which line our program crashed on. While your program has already exited, and you can't examine it for more information, the crash log is often very helpful in determining why your application crashed for a user.

You can actually configure the crash window to give you crash logs, as well, using the CrashReporterPrefs application, found in this directory:

/Developer/Applications/Utilities/

CrashReporterPrefs allows you to configure Crash Reporter for Developer mode. When in Developer mode, you can view crash logs right in the GUI when the application crashes, as shown in Figure 11. However, you get this crash dialog whenever any application crashes, not just ones you've written, so you may find this behavior too annoying to leave Developer mode on by default.


Figure 11: Crash dialog in Developer mode

Xcode Configurations

Take a look in the Xcode toolbar, and you'll notice the Overview item in the toolbar on the left hand side. It should say something like 10.5 | Debug | i386. To know what this means, click on the toolbar item, and you'll see a menu similar to Figure 12. You'll see that 10.5 corresponds to the Active SDK, Debug corresponds to the Active Configuration, and i386 corresponds to the Active Architecture. A full description of all these items is beyond the scope of this article, but we're going to briefly talk about the Active Configuration and Active Architecture settings.


Figure 12: Xcode overview menu

By default, Xcode uses the Debug configuration. You'll notice there is also a Release configuration. This is because your application needs to be compiled in a special manner to work properly with the debugger. When you compile with the Release configuration, your application will be faster and use less disk space, so you will want to use it before distributing your application to your users. However, it may not work well with the debugger. You may have trouble setting breakpoints, and the stack traces included when your application crashes may not be as accurate. For example, it may not be able to tell you exactly which line your application crashed on.

Also, in the Debug configuration, your application is only compiled for the Active Architecture, which speeds up compile times. In contrast, the Release configuration will compile your application as a Universal binary and will run natively on both PowerPC and Intel Macs. However, this means your code is compiled twice and can slow down development time.

The Active Architecture is the architecture of your current hardware: if you are running on an Intel Mac, the architecture will be set to i386. If you're on a PowerPC Mac, the architecture will be set to ppc. This means that your application will only run natively on the same type of Mac that you have.

Because of the differences between Debug and Release configurations, you will typically use Debug while developing your application and Release to build the final version you ship to your users. Just be aware that you will not be able to accurately debug that final version or get accurate stack traces if your application crashes.

Conclusion

This article has given you a brief overview of how to use logging and Xcode's integrated debugger to help you diagnose and fix errors in your programs. Debugging is an art in and of itself, and just like programming, the more you do it, the better you get at it. There are lots of resources on the Internet about debugging in general as well as specifics on how to use gdb and the Xcode debugger. For instance, Apple has a good article called "Technical Note TN2124: Mac OS X Debugging Magic" on their website. This article is chock full of tips and tricks of debugging techniques for Mac OS X and a worthy read.

Bibliography

"Technical Note TN2124" http://developer.apple.com/technotes/tn2004/tn2124.html


Dave Dribin has been writing professional software for over eleven years. After five years programming embedded C in the telecom industry and a brief stint riding the Internet bubble, he decided to venture out on his own. Since 2001, he has been providing independent consulting services, and in 2006, he founded Bit Maki, Inc. Find out more at http://www.bitmaki.com/ and http://www.dribin.org/dave/.

 
AAPL
$98.15
Apple Inc.
-0.23
MSFT
$43.58
Microsoft Corpora
-0.31
GOOG
$587.42
Google Inc.
+1.81

MacTech Search:
Community Search:

Software Updates via MacUpdate

Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0 - Drag-and-drop Web desi...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Drive Genius 3.2.4 - Powerful system uti...
Drive Genius is an OS X utility designed to provide unsurpassed storage management. Featuring an easy-to-use interface, Drive Genius is packed with powerful tools such as a drive optimizer, a... Read more
Vitamin-R 2.15 - Personal productivity t...
Vitamin-R creates the optimal conditions for your brain to work at its best by structuring your work into short bursts of distraction-free, highly focused activity alternating with opportunities for... Read more
Toast Titanium 12.0 - The ultimate media...
Toast Titanium goes way beyond the very basic burning in the Mac OS and iLife software, and sets the standard for burning CDs, DVDs, and now Blu-ray discs on the Mac. Create superior sounding audio... Read more
OS X Yosemite Wallpaper 1.0 - Desktop im...
OS X Yosemite Wallpaper is the gorgeous new background image for Apple's upcoming OS X 10.10 Yosemite. This wallpaper is available for all screen resolutions with a source file that measures 5,418... Read more
Acorn 4.4 - Bitmap image editor. (Demo)
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
Bartender 1.2.20 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more

Latest Forum Discussions

See All

Empire Manager (Games)
Empire Manager 1.0 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: Become ruler of an empire. Manage your economy, develop technology, hire an army and conquer the world in this addictive turn-... | Read more »
Empire Manager HD (Games)
Empire Manager HD 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: Become ruler of an empire. Manage your economy, develop technology, hire an army and conquer the world in this addictive... | Read more »
Star Admiral Review
Star Admiral Review By Rob Thomas on July 30th, 2014 Our Rating: :: ADMIRABLE ADMIRALSUniversal App - Designed for iPhone and iPad While this new digital CCG may feel a bit familiar, Star Admiral offers a sci-fi twist and galaxy’s... | Read more »
Zap! Pow! Become a Badass Wizard in Phan...
Zap! Pow! | Read more »
Urban Trial Freestyle Review
Urban Trial Freestyle Review By Blake Grundman on July 30th, 2014 Our Rating: :: RIDIN' DIRTYUniversal App - Designed for iPhone and iPad A rough ride that has trouble keeping its wheels on the track.   | Read more »
Take Note! Noteshelf Has Recieved a Big...
Take Note! Noteshelf Has Recieved a Big Update. Posted by Jessica Fisher on July 30th, 2014 [ permalink ] iPad Only App - Designed for the iPad | Read more »
Cubama Review
Cubama Review By Nadia Oxford on July 30th, 2014 Our Rating: :: TETRIIIIIS IIIIIN SPAAAAACE!Universal App - Designed for iPhone and iPad With its addictive challenge and interesting premise, Cubama is frantic screen-tapping fun.   | Read more »
Become a Guardians of Galactic Peace Wit...
Become a Guardians of Galactic Peace With the New Spacefaring Sim, Kairobotica. Posted by Jessica Fisher on July 30th, 2014 [ permalink ] | Read more »
Soul Guardians: Age of Midgard Review
Soul Guardians: Age of Midgard Review By George Fagundes on July 30th, 2014 Our Rating: :: SO MUCH GRIND IT CRUNCHESUniversal App - Designed for iPhone and iPad Swords and trading cards are fun, right? So is Soul Guardians: Age of... | Read more »
NFL Fantasy Football App Redesigned Ahea...
NFL Fantasy Football App Redesigned Ahead of Upcoming 2014 Season Posted by Ellis Spice on July 30th, 2014 [ permalink ] | Read more »

Price Scanner via MacPrices.net

More iPad Upgrade Musings – The ‘Book Mystiqu...
Much discussed recently, what with Apple reporting iPad sales shrinkage over two consecutive quarters, is that it had apparently been widely assumed that tablet users would follow a two-year hardware... Read more
13-inch 2.5GHz MacBook Pro on sale for $999,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $999.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $100 off MSRP. Price is... Read more
Save up to $300 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more
WaterField Unveils 15″ Outback Solo & 13″...
Hard on the heels of Apple’s refreshed MacBook Pro Retina laptops announcement, WaterField Designs has unveiled a 15-inch version of the waxed-canvas and leather Outback Solo and a 13-inch version of... Read more
New Roxio Toast 12 Delivers Digital Media Pow...
Roxio Toast 12 is a hub for sharing digital media to virtually any platform or device. has introduced two new additions to its Roxio Toast product family – Roxio Toast 12 Titanium and Roxio Toast 12... Read more
The lowest prices on leftover Retina MacBook...
Best Buy has dropped prices on leftover 13″ and 15″ Retina MacBook Pros by up to $300 off original MSRP on their online store for a limited time. Choose free local store pickup (if available) or free... Read more
Apple Updates MacBook Pro with Retina Display...
Apple today updated its MacBook Pro with Retina display with faster processors and double the amount of memory in both entry-level configurations. MacBook Pro with Retina display features a Retina... Read more
Up to $250 price drop on leftover 15-inch Mac...
B&H Photo has dropped prices on 2013 15″ Retina MacBook Pros by as much as $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.3GHz Retina MacBook Pro: $2349... Read more
Updated MacBook Pro Price Trackers
We’ve updated our MacBook Pro Price Trackers with the latest information on prices, bundles, and availability on the new 2014 models from Apple’s authorized internet/catalog resellers as well as... Read more
Apple updates MacBook Pros with slightly fast...
Apple updated 13″ and 15″ Retina MacBook Pros today with slightly faster Haswell processors. 13″ models now ship with 8GB of RAM standard, while 15″ MacBook Pros ship with 16GB across the board. Most... Read more

Jobs Board

Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.