TweetFollow Us on Twitter

The Road to Code: Nice and Gooey

Volume Number: 24 (2008)
Issue Number: 04
Column Tag: The Road to Code

The Road to Code: Nice and Gooey

Writing your first Cocoa GUI interface

by Dave Dribin

Graphical User Interfaces

This is the tenth article in The Road to Code, and we have yet to write an application with a graphic user interface, or GUI. We've stuck to writing command line applications, which may seem strange, given that Mac OS X is considered one of the best GUI environments. But, as with learning many complex topics, you've got to learn the basics before moving on to the more advanced topics. Well, you'll be happy to know that we finally reached the point where we can start writing GUI applications for Mac OS X in Objective-C. Congratulations!

Leopard Only

A word of warning before getting too deep: now that Mac OS 10.5 (Leopard) is available, I will be writing all examples in Xcode 3 and Interface Builder 3, the new integrated development environment, or IDE, that comes with Leopard. This will not only affect Interface Builder screenshots and instructions, but the code will also be targeted to Leopard, as well. I will be making liberal use of Objective-C 2.0 properties, fast enumeration, and garbage collection. These new features can simplify code and make it more readable, so I think all new code going forward should take advantage of them. Since we haven't gone over these topics outside of the Leopard Detour article, I'll be going over them in more detail as we come across them. If you don't have Leopard or want to target previous version of Mac OS X, the simple examples we'll be going over for the time being can be built with minor modifications on Xcode 2.4.1 and Interface Builder 2.5. I'll try to point out any potential areas that are not backward compatible.

With the technicalities out of the way, let's get started. Open up Xcode 3 and select the File > New Project... menu. Choose Cocoa Application as in Figure 1.


Figure 1: New Cocoa application project

Name the project Hello World and click Finish. So far, this is the same as creating a new Foundation Tool application as we have been doing previously. However, this project has a different layout than command line tools. If you open some of the disclosure triangles in the Groups & Files section on the left, you should see a list of files similar to those shown in Figure 2.


Figure 2: Cocoa Application default files

You'll notice it creates more than the single .m file that we have seen thus far. It creates a main.m source file and a few other resources. We'll talk about all these files in a second, but it turns out that this program is ready to run. So let's not waste anymore time and see what Xcode gives us by default. If you select Build and Go from the toolbar or Run > Run from the menu bar, this will start our new application. You will get a new empty window, as in Figure 3.


Figure 3: Hello World window

That's pretty basic, but it's a fully functional Cocoa GUI application. You even get a menu bar, as shown in Figure 4. In fact, you need to quit our application to return to Xcode so choose Hello World > Quit NewApplication to do this now.


Figure 4: Hello World menu bar

You many have noticed the "NewApplication" text in the Hello World menu, as shown in Figure 5. Xcode doesn't setup the menus with the name of our application automatically. But don't fret, we can edit the menus to our heart's content, and we'll change this text in a bit.


Figure 5: Hello World quit menu

Before going further, let's take a quick look at the source code that Xcode generates for us. There's only one source file and that's main.m. Select that to see what's inside. If you're expecting to see a bunch of code that sets up the menus and creates a window, you'll be sorely disappointed. Our main function is quite small. In fact it's only a single line:

Listing 1: main function for Cocoa applications

#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc,  (const char **) argv);
}

That's all the code running this application. The only other source file is the Hello World_Prefix.pch file, and this file is only used to help speed up compile times. It's called a prefix header and can generally be ignored. So where do the window and menus come from?

Interface Builder

If you look in the Resources group, you'll notice a file named MainMenu.nib. A nib file contains all the GUI components of a Cocoa application in a sort of freeze-dried state. These nib files cannot be edited in Xcode, however. There is a new application called Interface Builder for this. Double click on MainMenu.nib and Xcode will automatically open this file for you in Interface Builder. As a historic note, the nib file extension stands for NeXT Interface Builder and once again shows the NeXT lineage of Mac OS X.

Once this file is opened up in Interface Builder, you will be presented with a myriad of new windows. I've shown a bird's-eye view of all the windows in Figure 6.


Figure 6: Interface Builder windows

The two panel windows on the right are not part of our nib. The first one with the Window Identity title is the Inspector panel. This is how we change various attributes of our GUI components. The Library panel contains all the "parts" that we can add to our nib. The MainMenu.nib window contains all the "parts" that currently are part of our nib. Among these components you'll see MainMenu and Window. These correspond to the freeze-dried main menu and window of the Hello World application. The other two windows correspond to editable copies of the main menu and window of our application, which is how we change them.

Let's start by adding a text label to our window. You'll need to find the Label component in the Library. The easiest way to do this is to type "label" into the search field. Once you find it, drag it from the Library panel onto your Window, as shown in Figure 7.


Figure 7: Adding a label to our window

Now that you have the label placed in your window, you can change the text. Double click on it and change the text to "Hello World". You can also move the label anywhere you like, just by dragging. If you switch back to Xcode and run the application, the window should have our new label in it, as shown in Figure 8.


Figure 8: Running Hello World with the new label

See how easy that was? We were able to add a label to our application without even writing a single line of code. Interface Builder is a powerful GUI editor. As you start writing more complex GUI applications, you will be spending a lot of time in Interface Builder, as well as Xcode.

Changing the Menus

Before we start adding some custom code to our application, let's fix up the application name in the menus. Go back to Interface Builder and click in the window that looks like a menu bar. You should be able to open the menus and see all the menu items, just like a normal menu bar. However, you can now double click on the menus or menu items to change the text. For example, to change the text "About NewApplication" to "About Hello World," open up the NewApplication menu and double click on the About NewApplication menu item. You should now be editing the text, as shown in Figure 9. Change the text appropriately and hit Return.


Figure 9: Editing a menu

Now do the same with the Hide and Quit menu items, as well as the NewApplication menu in the menu bar. The final result should look like Figure 10.


Figure 10: Edited menu

If you now go back to Xcode and run the application, you should see our edited menus.

Actions

While you can do a lot using Interface Builder alone, you do end up having to write code that interacts with the user interface. Interface Builder provides ways to hook up parts of the user interface with code, as well. Let's add a button to our window, but first delete the label we added. Click on the label and delete it by pressing the Delete key. Now, we need to find a button in the Library. If you type "button" into the Library's search field, you will see a bunch of different button styles to choose from. The standard Cocoa button is called a Push Button and is the first one in the list, as shown in Figure 11. Drag the push button to your main window and change its text to "Press Me," as shown in Figure 12.


Figure 11: Buttons in the library


Figure 12: Press Me button

You can run the application as is, and you can even press the button, but nothing will happen. We need to hook up the button to some code so we can do something when the user presses it.

Let's create a new class in Xcode and name it HelloWorldController. Xcode will create the empty header and the implementation files, as usual. We're going to create a method that gets called when the button is pressed. Make the header and source file match Listing 2 and Listing 3, respectively, and save both files.

Listing 2: HelloWorldController.h

#import <Cocoa/Cocoa.h>
@interface HelloWorldController : NSObject
{
}
- (IBAction) pressMe: (id) sender;
@end

Listing 3: HelloWorldController.m

#import "HelloWorldController.h"
@implementation HelloWorldController
- (IBAction) pressMe: (id) sender;
{
    NSLog(@"Button pressed");
}
@end

This class contains one method, pressMe:, that prints a message to the console when called. This method has a very special signature. It returns a type called IBAction, and it takes one argument of type id. The IBAction return type is really the same as void, meaning there is no return value, with the exception that it marks this method as an action method for Interface Builder. We haven't yet covered the id type, but it's not really important for this discussion. We'll tackle id in a future article. What's important is that action methods take a single id argument.

Marking a method as an action method means you can access this method from Interface Builder. Before we can use it, we need to create an instance of HelloWorldController that Interface Builder can see. Go back to Interface Builder and search for "nsobject" to find the Object component in the Library. Drag this over to the MainMenu.nib window, as shown in Figure 13.


Figure 13: Adding an NSObject to your nib

Now go to the Inspector panel, and click on the Identity tab; it's the sixth tab from the left with the little "i" in a circle icon. Change the class to HelloWorldController and hit Return. The panel should now look like Figure 14. If Interface Builder does not allow you to choose HelloWorldController, be sure you've saved your files in Xcode.


Figure 14: Setting the class of an NSObject

You'll notice that once the class is set to HelloWorldController, the pressMe: method also shows up in the Class Actions section. If you don't see this action then double check your code to make sure you spelled everything correctly. By adding our object to the nib, we've created a freeze-dried instance of our class. This means that one instance of our class will automatically be created when the application starts.

With our object in place and our action visible to Interface Builder, we can hook up the action to our button. You do this by control dragging from the button to the Hello World Controller. By "control dragging" I mean you must press and hold the Control key while clicking and dragging. This action may be a bit strange, but you will use it a lot in Interface Builder. You should see a blue line follow your mouse as you drag. After you release the mouse button on top of our object, you'll get a popup window of possible actions you can connect the button to, as shown in Figure 15. Click on pressMe: and Interface Builder will flash a bit to confirm that it hooked up the action.


Figure 15: Hooking up a button to an action

That's it! You have now hooked up the button to our action method. Let's go back to Xcode and run our application to see if it worked. After our application launches, click the button a few times and check the console for any output. Xcode 3 no longer shows the Console window by default, but you can open it with the Run > Console command, or Command-Shift-R. If the action was properly hooked up in Interface Builder, you should see output in the console similar to this:

2008-02-06 10:43:15.479 Hello World[5864:10b] Button pressed
2008-02-06 10:43:16.079 Hello World[5864:10b] Button pressed
2008-02-06 10:43:19.479 Hello World[5864:10b] Button pressed

If you want to always see the Console window like previous versions of Xcode (I do), you can change this in the Xcode preferences. Under the Debugging tab, in the On Start popup, choose Show Console.


Figure 16: Received actions

Since actions are a two-way relationship, you can also verify this by viewing the connections of the button.

Push buttons are not the only GUI components that send actions. Menu items, checkboxes, radio buttons, and popup buttons all send actions. The procedure for hooking these up is always the same. Create an action method in your code and then control drag in Interface Builder to hook up a component to an action. Now that you know how to do it, I won't go over the detailed procedure in the future.

Outlets

Actions are great, but that's only half the puzzle. We still need to be able to get information out of the GUI. If we have a text field, for example, we will probably want to use what the user entered into it. Let's cover that now.

Find the Text Field component in the Library by searching for "text field" and add it to the window by dragging it from the Library, just like we did with the label and button. Be sure not to mistakenly choose the Text Field Cell, which is not the same thing. Place the text field above the button, as shown in Figure 17.


Figure 17: Added text field

If we now run the application, you will be able to type into the text field, as you might expect. Getting what you type out of the text field requires some code. Back in Xcode, add an instance variable named _textField to our class, as shown in Listing 4, and save the file.

Listing 4: HelloWorldController.h with an outlet

#import <Cocoa/Cocoa.h>
@interface HelloWorldController : NSObject
{
    IBOutlet NSTextField * _textField;
}
- (IBAction) pressMe: (id) sender;
@end

This instance variable is declared like any other instance variable, except it has the IBOutlet prefix before the type. Again, this is for integration with Interface Builder and marks this instance variable as an outlet. Outlets can be hooked up to GUI components in Interface Builder, and that's the next step.

Back in Interface Builder, control drag from the Hello World Controller to the text field. Again, when you release the button, you should get a popup window allowing you to select _textField, as shown in Figure 18. Choose _textField to make the connection. You can verify the connection by looking at the Connection tab of the Inspector panel, if you like.


Figure 18: Hooking up an outlet

With the outlet connection made, we can now use our _textField instance variable. It will automatically be set at application load time. You'll notice the type of _textField is NSTextField. This is the Cocoa class for text field controls. It has many methods, but the one we are interested in is stringValue. This method, unsurprisingly, returns the contents of the text field as an NSString. Modify our action method to log this value when the button is pressed, as shown in Listing 5.

Listing 5: HelloWorldController.m using an outlet

#import "HelloWorldController.h"
@implementation HelloWorldController
- (IBAction) pressMe: (id) sender;
{
    NSLog(@"Button pressed");
    NSLog(@"Text field is: %@", [_textField stringValue]);
}
@end

Now run the application again. Type some text into the text field, such as "Hello!", and press the button. You should see text in the console window similar to:

2008-02-06 11:57:50.697 Hello World[6089:10b] Button pressed
2008-02-06 11:57:50.698 Hello World[6089:10b] Text field is: Hello!

You've just hooked up and used your first outlet! Outlets can be used to hook up any GUI component to your code. They are used quite a bit, as you will see once you start more Cocoa programming. With actions and outlets, we can create a real GUI application.

Rectangle Area Calculation

Let's bring back our old friend from a few articles ago, the Rectangle class. Add a new class named Rectangle to your application, and make sure the header and source files match Listing 6 and Listing 7, respectively.

Listing 6: Rectangle.h

#import <Foundation/Foundation.h>
@interface Rectangle : NSObject
{
    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

Listing 7: Rectangle.m

#import "Rectangle.h"
@implementation Rectangle
@synthesize leftX = _leftX;
@synthesize bottomY = _bottomY;
@synthesize width = _width;
@synthesize height = _height;
- (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;
}
- (float) area
{
    return _width * _height;
}
- (float) perimeter
{
    return (2*_width) + (2*_height);
}
@end

This Rectangle class is similar to what we've used in previous articles, except that I've updated it with Objective-C 2.0 properties. In the header file, you'll see several @property lines. These declare properties and must match the following syntax:

@property (options) type name;

The type is any valid Objective-C type, such as C primitives or Objective-C classes. In our case, we're using the float primitive type. One of the options available is readonly. We used this on the area and perimeter properties. Another option is readwrite. This is the default, which is why we don't specify it on the rest of our properties. The @property declaration declares accessor methods for us. A readonly property declares a getter method only, while a readwrite property declares both a getter and a setter. Thus, this single line:

@property float leftX; is the same as declaring these two methods: - (float) leftX; - (void) setLeftX: (float) leftX;

There are other options, but we don't need to know about them just yet. It gets even better. Inside the source file, the @synthesize keyword generates method implementations for us. Thus, this single line:

@synthesize leftX = _leftX;
is the same as these eight lines of code:
- (float) leftX;
{
    return _leftX;
}
- (void) setLeftX: (float) leftX;
{
    _leftX = leftX;
}

As you can see, properties can save us lots of monotonous typing. You do need to match up property names to instance variables, but that's a small price to pay. And as a bonus, if you name your instances variables the same as your properties, you don't need the "=" part of the @synthesize lines. I still prefer underscore prefixes for my instance variables, but that's just personal taste.

You'll notice that we still implement the area and perimeter methods. This is completely legal, and it shows how you can mix property declarations and custom method implementations, if you need to do so. We need to do it because these methods are calculations and have no corresponding instance variables.

Since properties are Leopard-only, this code will not compile in previous versions of Xcode. If you want to run this on earlier versions of Xcode and Mac OS X, you'll need to replace all the @property lines with their corresponding accessor methods.

We're now going to create a GUI around this Rectangle class to allow the user to perform area and perimeter calculations. First, set up our user interface in Interface Builder. Drag labels, text fields, and a button into the window, and resize the window so it looks like Figure 19.


Figure 19: Rectangle window layout

When you're dragging things around and setting up the GUI, you will probably see dashed blue lines pop up, as shown in Figure 20. These are guides that give you hints about Apple's Human Interface Guidelines (HIG). The HIG is a document that specifies many guidelines about designing consistent user interfaces for Mac OS X. It's a big document, and a good read if you plan on doing any serious Cocoa development. Part of the information included in the HIG is spacing guidelines of components, such as how many pixels should be used as border for windows. Luckily, Interface Builder shows us these blue HIG guides so that we don't have to count pixels to make sure we're laying things out correctly.


Figure 20: Rectangle window with HIG guides

With our user interface in place, we need to go back into Xcode to hook up these components. Modify the HelloWorldController.h header file to match Listing 9.

Listing 9: HelloWorldController.h for rectangles

#import <Cocoa/Cocoa.h>
@class Rectangle;
@interface HelloWorldController : NSObject
{
    IBOutlet NSTextField * _widthField;
    IBOutlet NSTextField * _heightField;
    IBOutlet NSTextField * _areaLabel;
    IBOutlet NSTextField * _perimiterLabel;
    
    Rectangle * _rectangle;
}
- (IBAction) calculate: (id) sender;
@end

With these outlets and actions in place, save this file, go back to Interface Builder, and make the appropriate connections. If you did it properly, the connections for Hello World Controller should look like Figure 21.


Figure 21: Connections for Hello World Controller

Now, we can finish implementing our controller class. Modify the HelloWorldController.m source file to match Listing 10.

Listing 10: HelloWorldController.m for rectangles

#import "HelloWorldController.h"
#import "Rectangle.h"
@implementation HelloWorldController
- (id) init
{
    self = [super init];
    if (self == nil)
        return nil;
    
    _rectangle = [[Rectangle alloc]   initWithLeftX: 0
                                         bottomY: 0
                                          rightX: 5
                                            topY: 10];
    
    return self;
}
- (void) updateAreaAndPerimeter
{
    [_areaLabel setFloatValue: _rectangle.area];
    [_perimiterLabel setFloatValue: _rectangle.perimeter];
}
- (IBAction) calculate: (id) sender
{
    _rectangle.width = [_widthField floatValue];
    _rectangle.height = [_heightField floatValue];
    [self updateAreaAndPerimeter];
}
- (void) awakeFromNib
{
    [_widthField setFloatValue: _rectangle.width];
    [_heightField setFloatValue: _rectangle.height];
    [self updateAreaAndPerimeter];
}
@end

We've had to beef this up a bit, but it's still pretty simple. In our constructor, we create a new Rectangle instance with a width of 5 and a height of 10. Our calculate: action sets the rectangle's width and height from the text fields, using the floatValue method. It then calls updateAreaAndPerimiter to set the area and perimeter labels according to the rectangle's current area and perimeter. This code also demonstrates another benefit of properties: you can use the dot notation to access them. Thus, instead of calling setter methods:

- (IBAction) calculate: (id) sender
{
    [_rectangle setWidth: [_widthField floatValue]];
    [_rectangle setHeight: [_heightField floatValue]];
    [self updateAreaAndPerimeter];
}

we can use the dot notation, _rectangle.width =, as shown in Listing 10.

The only other new bit is the awakeFromNib method. This is called automatically by Cocoa at application startup. We use this to set up the initial values of the text fields and labels when our application is started. You'd think we could do this in our constructor, but there's a bit of a problem with that.


Figure 22: Initial Hello World window

Remember that objects inside a nib file are "freeze-dried" or "put to sleep" when Interface Builder saves the nib file. When you application runs, these saved objects are "reconstituted" or "awoken" at application launch time. The problem is that we don't know what order these objects are awoken and created. Thus, the text fields and labels may not be initialized when our constructor is called. To get around this situation, Cocoa first instantiates all sleeping objects in the nib, and then calls awakeFromNib on each of these objects. You don't have to implement awakeFromNib, but we take this opportunity to setup the initial GUI state. As a rule, if you need to work with outlets, you must not do so in the constructor. Use the awakeFomNib method. Thus, when our application is first run, you will see a window that looks like Figure 22 (above).

We can now change the width and height and click the Calculate button. If everything went as planned, the area and perimeter will be updated as shown in Figure 23.


Figure 23: Calculated area and perimeter

Conclusion

Well, how about that! You've created your first honest-to-goodness Mac OS X GUI application. As you can see, it often does not take that much code to produce nice looking user interfaces. Interface Builder is the key to this ease. Now that you've got the basics of Interface Builder and GUI Mac OS X applications down, we can move on to bigger and better topics. The full source to the project will be available for download from the MacTech website.


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
$118.93
Apple Inc.
-0.07
MSFT
$48.12
Microsoft Corpora
+0.37
GOOG
$541.03
Google Inc.
+0.66

MacTech Search:
Community Search:

Software Updates via MacUpdate

Skype 7.2.0.412 - Voice-over-internet ph...
Skype allows you to talk to friends, family and co-workers across the Internet without the inconvenience of long distance telephone charges. Using peer-to-peer data transmission technology, Skype... Read more
HoudahSpot 3.9.6 - Advanced file search...
HoudahSpot is a powerful file search tool built upon MacOS X Spotlight. Spotlight unleashed Create detailed queries to locate the exact file you need Narrow down searches. Zero in on files Save... Read more
RapidWeaver 6.0.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
iPhoto Library Manager 4.1.10 - Manage m...
iPhoto Library Manager lets you organize your photos into multiple iPhoto libraries. Separate your high school and college photos from your latest summer vacation pictures. Or keep some photo... Read more
iExplorer 3.5.1.9 - View and transfer al...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
OneNote 15.4 - Free digital notebook fro...
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

Latest Forum Discussions

See All

7 tips to get ahead of the competition i...
7 tips to get ahead of the competition in Dynasty of Dungeons Posted by Simon Reed on November 28th, 2014 [ permalink ] Playcrab has launched their action-packed new dungeon crawler, Dynasty of Dungeons, today. | Read more »
Monster Strike Review
Monster Strike Review By Campbell Bird on November 28th, 2014 Our Rating: :: BILLIARD STRATEGYUniversal App - Designed for iPhone and iPad Collect monsters and battle by flinging them across the battlefield in this strangely... | Read more »
Proun+ Review
Proun+ Review By Jennifer Allen on November 28th, 2014 Our Rating: :: TWITCHY RACINGUniversal App - Designed for iPhone and iPad Twitchy racing aplenty in Proun+, an enjoyably tricky title.   | Read more »
Lucha Amigos (Games)
Lucha Amigos 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Forget Ninja Turtles, and meet Wrestlers Turtles! Crazier, Spicier and…Bouncier! Sling carapaces of 7 Luchadores to knock all... | Read more »
Record of Agarest War Zero (Games)
Record of Agarest War Zero 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: HyperDevbox Holiday Turkey Black Friday Special Pricing! To celebrate the opening of the holiday season HyperDevbox... | Read more »
Raby (Games)
Raby 1.0.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.3 (iTunes) Description: ***WARNING - Raby runs on: iPhone 5, iPhone 5C, iPhone 5S, iPhone 6, iPhone 6 Plus, iPad Mini Retina, iPad Mini 3, iPad 4, iPad Air,... | Read more »
Oddworld: Stranger's Wrath (Games)
Oddworld: Stranger's Wrath 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: ** PLEASE NOTE: Oddworld Stranger's Wrath requires at least an iPhone 4S, iPad 2, iPad Mini or iPod Touch 5th gen... | Read more »
Bounce On Back (Games)
Bounce On Back 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Dwelp (Games)
Dwelp 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: === 50% off for a limited time, to celebrate release === Dwelp is an elegant little puzzler with a brand new game mechanic. To complete a... | Read more »
Make Way for Fat Chicken, from the Maker...
Make Way for Fat Chicken, from the Makers of Scrap Squad Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Relevant Games has announced they will be releasing their reverse tower defense game, | Read more »

Price Scanner via MacPrices.net

Black Friday: Up to $60 off Mac minis, NY tax...
 B&H Photo has new 2014 Mac minis on sale for up to $60 off MSRP as part of their Black Friday sale. Shipping is free, and B&H charges NY sales tax only: - 1.4GHz Mac mini: $449.99 $50 off... Read more
Black Friday: 27-inch 5K iMac for $2299, save...
 B&H Photo continues to offer Black Friday sale prices on the 27″ 3.5GHz 5K iMac, in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP... Read more
Karalux Announces 24K Gold-Plated iPhone 6
Karalux, a Vietnam-based jewellery firm, has launched a unique 24 karat gold-plated iPhone 6 version with gold-cast monolithic dragon on its back panel. The real 24 karat gold plated enclosure doesn’... Read more
Black Friday: 13-inch 2.6GHz Retina MacBook P...
 B&H Photo has lowered their price for the 13″ 2.6GHz/128GB Retina MacBook Pro to $1159 for Black Friday. That’s $140 off MSRP, and it’s the lowest price for this model (except for Apple’s $1099... Read more
View all the Black Friday sales on our Mac Pr...
We’ve updated our Mac Price Trackers with the latest information on prices, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. View Black Friday sale prices at a... Read more
Black Friday: 11-inch MacBook Air for $779, s...
 Best Buy has lowered their price for the 2014 11″ 1.4GHz/128GB MacBook Air to $779.99 for Black Friday. That’s $120 off MSRP. Choose free shipping or free local store pickup (if available). Sale... Read more
Apple Store Black Friday sale for 2014: $100...
BLACK FRIDAY The Apple Store has posted their Black Friday deals for 2014. Receive a $100 PRODUCT(RED) branded iTunes gift card with the purchase of select Macs, $50 with iPads, and $25 with iPods,... Read more
Black Friday: 15% off iTunes Gift Cards
Staples is offering 15% off $50 and $100 iTunes Gift Cards on their online store as part of their Black Friday sale. Click here for more information. Shipping is free. Best Buy is offering $100... Read more
BEVL Releases Dock Tailored for iPhone 6 and...
Seattle based BEVL has released their first product: an iPhone dock that is divergent in build quality, rock-solid function and visual simplicity to complement the iPhone. BEVL is now accepting... Read more
Black Friday: $150 off 13-inch Retina MacBook...
 Best Buy has 13-inch 2.6GHz Retina MacBook Pros on sale for $150 off MSRP on their online store as part of their Black Friday sale. Choose free shipping or free local store pickup (if available).... Read more

Jobs Board

*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
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Retail - Multiple Positions (US) - A...
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
*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
*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.