TweetFollow Us on Twitter

The Road to Code: More Cocoa Bits

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

The Road to Code: More Cocoa Bits

Interface Builder UI tweaking and introduction to table view

by Dave Dribin

Customizing the User Interface

Last month in The Road to Code we went over how to customize application behavior using notifications and delegates. This month we're going start off talking about how you can customize the user interface in Interface Builder. There's a lot you can tweak without writing a line of code.

Window Resizing

One important aspect of user interface design is how the window and its views and controls react to resizing. Improper resizing may confuse the user and lead to a bad user experience. You control how resizing affects each and every view and control within Interface Builder. Unfortunately, the defaults are rarely useful. For example, if we resize our Hello World window with the default settings, it will look similar to Figure 1.

Figure 1: Improper window resizing

As you resize, all the controls will be bunched up in the upper-left portion of the window. This isn't really a good use of the extra space. The text fields on the right should expand to the full width of the window, and the Calculate button should also stick to the right side of the window. Thus we want the window to look similar to Figure 2 when resized.

Figure 2: Proper window resizing

I've also kept the Calculate button on the bottom of the window. You could also keep it pinned towards the top, but for demonstration purposes, I'm going to keep it on the bottom. In order to make our window properly resize like this, we need to open Interface Builder.

Select the text field next to the Rectangle Width label. Next, open up the Inspector panel and select the Size tab; it's third from the left with the ruler icon. It should look similar to Figure 3.

Figure 3: Size panel of the Inspector

This panel contains information about the size of the selected view. The Autosizing section is the part that dictates how the control behaves when the window is resized. The left portion of the autosizing section is called the springs and struts. There are six lines you can click on and activate, two on the inside and four on the outside. The two on the inside are called springs and the four on the outside are called struts as noted in Figure 4.

Figure 4: Autosizing springs and struts

When a specific string or strut is activated, it is colored red and has a solid line. When not activated, it is colored light red with a dotted line. An activated spring indicates that the width or height of the view expands and contracts in proportion to its superview. An activated strut indicates that the view maintains a fixed distance between its edge and the same edge of its superview. The right portion of autosizing section is an animated preview showing you how the settings will affect the view. You should see the animation change as you activate and deactivate springs and struts.

The animated preview is handy, but sometimes you need to actually run the application and try resizing the window to verify your settings. While you can go back to Xcode and run the application, Interface Builder allows you to simulate the interface without switching to Xcode. Choose the File > Simulate Interface menu or Command-R to do this. While simulating the interface, you may resize the window and watch how the views react. When you are done, you need to quit the Cocoa Simulator using the menu or Command-Q. Between the animation preview and the simulator, you should be able to find the correct springs and struts settings for your application without ever switching to Xcode.

The default setting, as shown in Figure 4 above, is to have the top and left struts activated and no springs activated. This explains why all of our controls are bunched up in the upper left portion of the window. For our text fields, we want to activate the horizontal spring and the left, right, and top struts. This will cause them to resize horizontally while staying pinned on the left, right, and top. The final settings should look like Figure 5.

Figure 5: Autosizing for text fields

For the Calculate button, we don't want any springs activated. The default settings have only the top and left struts activated, so we need to change this again. We want only the right and bottom struts activated. This will keep the button pinned to the lower right portion of the window. The final settings should look like Figure 6.

Figure 6: Autosizing for button

Try simulating the user interface, and see if it behaves correctly. It should now work as shown in Figure 2. Once it works, save the nib file, switch back to Xcode, and run the application. Again, the controls should resize appropriately.

There's one final aspect of our resizing that's not quite right. While making the window bigger works fine, it is possible to resize the window so small such that not all of our controls will fit in the window. To prevent this, we can specify a minimum size for our window. The window's sizes can be viewed and set in the Size pane of the Inspector window, as well. If you select the window by clicking on its title bar the Size pane should look similar to Figure 7.

Figure 7: Window size

You can see that our window has neither a minimum nor maximum size. Click on the Has Minimum Size checkbox to enable a minimum size. I think the window as currently laid out makes a nice minimum size, so click the Use Current button to set the minimum size to the window's current size. If you now simulate the user interface, you should be able to resize the window larger and smaller, as before, but you should not be allowed to resize it any smaller than the defined size. This is perfect, so save the nib file. If you want, you may provide a maximum size, too. I'm going to keep the maximum size disabled so the user can make the window as large as they want.

Resizing the window in Interface Builder

You can now properly resize the window in a running application, but what about resizing the window in Interface Builder? You can resize the window by dragging the resize corner, just as in a running application. However, the controls inside the window do not resize according to their autosizing settings. This may be fine if you are resizing the window to make room for more views. However, if you just want to make the window larger or smaller, it can be a chore to go through and manually resize each view and control after resizing the window. Fortunately there is a trick. If you hold down the Command key while resizing the window in Interface Builder, the controls will also resize according to their autosizing settings. If, for some reason, you forget to hold down Command while resizing the window, Interface Builder allows you to undo the resize. Then you can redo it while holding down the Command key.

Formatters

By default, text fields can display and accept any text. Sometimes, however, the text fields need stricter formatting. Our rectangle program is a perfect example. The rectangle values are all floating point numbers. Maybe we would like to control how many decimal points are displayed. Also, our user interface doesn't stop the user from entering letters into the width and height fields. Other applications may like to format numbers in text fields as currency or percentages.

Luckily Cocoa has just the solution for us, called formatters. Formatters can be added to any text field to customize how objects are presented to the user. Interface Builder comes with two built-in types of formatters that you will use frequently: number formatters and date formatters. Number formatters take a number, usually a floating point number, and format it better. They are quite flexible and can be used to customize how decimal points are used, as well as allowing you to add comma separators for numbers over a thousand and format numbers as currency and percentages. To apply a formatter to a text field, drag it from the Library panel on top of a text field, as in Figure 8. Date formatters are used to customize the presentation of NSDate objects.

Figure 8: Adding a number formatter

The formatter is now attached to the text field. Interface Builder shows this by adding an icon of the formatter just below the text field as shown in Figure 9.

Figure 9: Text field with an attached formatter

By clicking on the formatter icon, you can change its attributes. Click on the formatter now, and the Attributes pane of the Inspector panel should update as in Figure 10. The Style pull-down menu offers various pre-configured formats. Set the Style to be Decimal.

Figure 10: Number formatter attributes

Now add a formatter with the Decimal style to the other numeric text fields, as well. If you would like, you can customize the decimal field to show one digit after the decimal point by setting the Minimum Fraction Digits to 1. When you run the application with formatters in place, numbers over 1,000 should be formatted appropriately as shown in Figure 11.

Figure 11: An application with formatters

Formatters not only convert from an object to text, but they also convert text back into an object. For number formatters, they are converted to NSNumber objects. The most important benefit we get out of using number formatters for input is that it restricts the user input to numbers only. If the user enters letters, the formatter will remove them from the text field.

With the autosizing properly set up, the minimum window size in place, and formatters on the text fields, our user interface is now nicely polished. And we didn't have to write a single line of code. All the tweaking was done using Interface Builder. The final code for this project may be found on the MacTech website.

Table Views

I'd like to shift gears a bit and get back to code and talk about a popular control called a table view. A table view is a control, like buttons and text fields, and is implemented by the NSTableView class. It displays rows and columns of information, similar to a spreadsheet application. It is a powerful control that is used in many applications.

Because a table view may display large amounts of information, the view class itself does not hold all the data. Instead, the table view requires a separate class that provides the data called a data source. Whenever the table view needs to display data for a specific row and column, it asks the data source for this information.

In last month's article, we talked about notifications and delegates as a way to customize user interface behavior in code, and data sources are very similar to delegates. A data source class must also implement specific methods. A table view may have both a delegate and a data source. The table view's delegate is only used for customizing the behavior of the view itself, just like the window and application delegates from last month. The same class may even implement the table view data source and delegate methods.

Let's go over a simple example of a table view and its data source. We're going to ignore the table view delegate and use the default behavior. Create a new Cocoa Application project in Xcode and open up its MainMenu.nib file in Interface Builder. You should have a blank window. Now, find the table view in the Library panel and drag it to the window. Resize the table view so that there is a small border around all sides. Finally, active all the springs and struts for the table view. This should allow the table view to expand vertically and horizontally as the window is resized.

Next, let's look at the attributes for a table view that are available in Interface Builder. Because a table view is enclosed in a scroll view, it can sometimes be a bit tricky to choose the table view. With the Attributes pane of the Inspector panel selected, click on the table view. Most likely, this will select the outer scroll view, which will have attributes that look like Figure 12. You may customize how the scroll bars, or scrollers, are displayed from this panel. The default is fine for us.

Clicking on the table view again should select the table view itself, and the Attributes pane should look similar to Figure 13. Now you can customize attributes of the table view itself, such as how many columns it has and various selection possibilities. Again, we're going to leave the default settings, but we will be coming back to this shortly.

Figure 12: Scroll view attributes

Oh, and because selecting the scroll view and table view can be a bit tricky, I'm going to let you in on a little secret that may help out. You can customize how Interface Builder shows the components in the nib. If you select list mode from the toolbar, you will be presented with a hierarchical list of components, instead of just icons. From this view, you may open up the disclosure triangles to select the scroll view or table view directly, as in Figure 14. Using list mode is often very helpful in selecting nested views, such as table views, tab views, and split views.

With the table view selected, you can now select individual table columns and change their attributes. After selecting the first table column, set its title and identifier to Column 1 and One, respectively, as shown in Figure 15. Now change the second column to have its title and identifier to be Column 2 and Two, respectively.

Figure 13: Table view attributes

Figure 14: List mode of Interface Builder

Figure 15: Table column attributes

If you save the nib and run the application from Xcode, you should get a window and table view, but the table view should be empty. In order to get data into the table view, we need to implement a data source in code. Create a new Objective-C class and name it MyController. In order for this class to be a table view data source, it must implement at least two methods. Here's the first one:

- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView;
{
    return 3;
}

The purpose of this method is self-explanatory: it sets the number of rows for a given table view. While the number of columns is set in Interface Builder, the number of rows is set in your code. For demonstration purposes we are returning a constant value of 3, which means three rows will be displayed.

Every row and column refers to a particular value in the table called a table cell. The second method that you must implement provides the actual data for each cell:

- (id) tableView: (NSTableView *) tableView
objectValueForTableColumn: (NSTableColumn *) tableColumn
            row: (NSInteger) rowIndex
{
    NSString * identifier = [tableColumn identifier];
    return [NSString stringWithFormat:
            @"%@ %d", identifier, rowIndex];
}

This method gets called for each and every cell in the table. You'll notice that it passes a table column object, NSTableColumn, and a row index. You may be surprised that it does not pass a column index, too. The problem is that the user is free to re-order columns, and this would make the column index pretty useless. From column object, we can get the identifier we setup in Interface Builder. The identifier is a much more reliable value than the column index, thus you can see why using a unique and meaningful identifier is very useful. For testing purposes, we are returning a string using the table column identifier and the row index.

We're almost ready to run our application, but first we need to tell the table view that MyController is its data source. Be sure to save all your files in Xcode and switch to Interface Builder. Find NSObject in the Library panel and drag it to you MainMenu.nib window. Set the class of this new object to be MyController in the Inspector panel. This creates an instance of the MyController class inside the nib.

Hooking this object up to the table view is similar connecting a delegate. You need to control-drag from the table view to the controller object. Be sure you are dragging from the table view and not the scroll view or the table column. Use list mode, if you have trouble selecting the table view. Once you control-drag from the table view to the controller object, Interface Builder should popup a menu allowing you to choose the outlet for connection. Two choices exists for table views: dataSource and delegate. Choose dataSource from the menu, as shown in Figure 16.

Figure 16: Connecting a data source

Now, save the nib, switch back to Xcode, and run the application. If all goes well, you should see a window similar to Figure 17. There should be three rows in the table and the contents of each table cell should be a mix of the table column identifier and the row index. You can even re-order the table columns if you want, and the table cell values should remain the same.

Figure 17: Simple table application

A Useful Table Example

Admittedly, that example is not very useful, so let's spice it up. Let's bring back our trusty Rectangle class and create an application to show a list of rectangles along with their area and perimeters. Add the Rectangle.h and Rectangle.m files to your Xcode project. For reference, the header file is shown in Listing 1.

Listing 1: Rectangle.h header file

#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

Go to Interface Builder and select the table view. We need to setup our table with four columns, each with the following header titles: Width, Height, Area, and Perimeter. In the table view's attributes, set the number of columns to 4. Resize the window so that all four columns are available. Then, select each column and change the title and identifiers appropriately. In order to keep things simple, let's keep the identifiers the same as the titles. Finally, make sure each column is not editable. The attributes for the width column are shown in Figure 18. Make sure the other three columns are setup in a similar fashion.

Figure 18: Width column attributes

Just as we can add formatters to text fields, you can also add them to table columns. Add number formatters to each of the table columns by dragging from the Library to the text cells of each table column. Set their style to be Decimal, as we did earlier.

We are finished with the user interface, so save the nib and switch to Xcode. Our controller class will keep an array of rectangles and display them in the table. Let's start out by populating the array in our constructor with a few rectangles:

- (id) init
{
    self = [super init];
    if (self == nil)
        return nil;
    
    _rectangles = [[NSMutableArray alloc] init];
    
    Rectangle * rectangle;
    rectangle = [[Rectangle alloc] initWithLeftX   : 0
                                         bottomY: 0
                                          rightX: 10
                                            topY: 20];
    [_rectangles addObject: rectangle];
    // Without garbage collection you need:
    // [rectangle release];
    
    rectangle = [[Rectangle alloc] initWithLeftX   : 0
                                         bottomY: 0
                                          rightX: 500
                                            topY: 100];
    [_rectangles addObject: rectangle];
    // Without garbage collection you need:
    // [rectangle release];
    
    return self;
}

Be sure to add the _rectangles instance variable to the header file. Now, we're going to enable garbage collection for our project, too. This allows use to avoid releasing the rectangle instances and avoid implementing a destructor. Click on the project name in the Groups & Files list on the left. Then choose the File > Get Info menu to open up the Inspector panel. Select the Build tab, find the Objective-C Garbage Collection build setting and set it to Supported.

If you do not want to enable garbage collection, uncomment the release calls to rectangle and implement the dealloc method to release the _rectangles array. You also need to release the rectangle instances after adding them to the _rectangles array, as described in the comments. Remember the array retains objects, so you need to release them if you no longer need them.

Now we need to modify our data source methods to use the array of rectangles, instead of hard coded values. The numberOfRowsInTableView method is easy. It returns the number of elements in the _rectangles array:

- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
{
    return [_rectangles count];
}

The tableView:objectValueForTableColumn:row: method is a bit more complex. It needs to return the proper rectangle property based on the identifier. The other tricky part is that the method returns an id type. This means we need to wrap our float values inside an NSNumber instance, as well:

- (id) tableView: (NSTableView *) tableView
objectValueForTableColumn: (NSTableColumn *) tableColumn
            row: (NSInteger) rowIndex
{
    NSString * identifier = [tableColumn identifier];
    Rectangle * rectangle = [_rectangles objectAtIndex: rowIndex];
    float value;
    if ([identifier isEqualToString: @"Width"])
        value = rectangle.width;
    else if ([identifier isEqualToString: @"Height"])
        value = rectangle.height;
    else if ([identifier isEqualToString: @"Area"])
        value = rectangle.area;
    else if ([identifier isEqualToString: @"Perimeter"])
        value = rectangle.perimeter;
    
    return [NSNumber numberWithFloat: value];
}

Running our application now should result in a window similar to Figure 19. It should show our two rectangles, along with their corresponding area and perimeter.

Figure 19: Initial rectangle table

Try resizing the window and see if it works correctly. Also try editing the individual table cells. Because we setup our table columns to be uneditable, it should not be allowed. The full listings for MyController are shown in Listing 2 and Listing 3.

Listing 2: MyController.h header file

#import <Cocoa/Cocoa.h>
@interface MyController : NSObject
{
    NSMutableArray * _rectangles;
}
@end
#import "MyController.h"
#import "Rectangle.h"
@implementation MyController
Listing 3: MyController.m source file
- (id) init
{
    self = [super init];
    if (self == nil)
        return nil;
    
    _rectangles = [[NSMutableArray alloc] init];
    
    Rectangle * rectangle;
    rectangle = [[Rectangle alloc] initWithLeftX   : 0
                                         bottomY: 0
                                          rightX: 10
                                            topY: 20];
    [_rectangles addObject: rectangle];
    // Without garbage collection you need:
    // [rectangle release];
    
    rectangle = [[Rectangle alloc] initWithLeftX   : 0
                                         bottomY: 0
                                          rightX: 500
                                            topY: 100];
    [_rectangles addObject: rectangle];
    // Without garbage collection you need:
    // [rectangle release];
    
    return self;
}
- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
{
    return [_rectangles count];
}
- (id) tableView: (NSTableView *) tableView
objectValueForTableColumn: (NSTableColumn *) tableColumn
            row: (NSInteger) rowIndex
{
    NSString * identifier = [tableColumn identifier];
    Rectangle * rectangle = [_rectangles objectAtIndex: rowIndex];
    float value;
    if ([identifier isEqualToString: @"Width"])
        value = rectangle.width;
    else if ([identifier isEqualToString: @"Height"])
        value = rectangle.height;
    else if ([identifier isEqualToString: @"Area"])
        value = rectangle.area;
    else if ([identifier isEqualToString: @"Perimeter"])
        value = rectangle.perimeter;
    
    return [NSNumber numberWithFloat: value];
}
@end

Conclusion

Once again, we've covered a lot of ground in just one article. There's a lot more we can do with a table view, too much to cover in a single article. Next month, we'll explore how to add and remove rectangles from the table. That is, if you haven't gone ahead and figured it out on your own.


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
$97.03
Apple Inc.
-0.16
MSFT
$44.40
Microsoft Corpora
-0.47
GOOG
$593.35
Google Inc.
-2.63

MacTech Search:
Community Search:

Software Updates via MacUpdate

Audio Hijack Pro 2.11.0 - Record and enh...
Audio Hijack Pro drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio with Audio Hijack... Read more
Intermission 1.1.1 - Pause and rewind li...
Intermission allows you to pause and rewind live audio from any application on your Mac. Intermission will buffer up to 3 hours of audio, allowing users to skip through any assortment of audio... Read more
Airfoil 4.8.7 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more
Microsoft Remote Desktop 8.0.8 - Connect...
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
xACT 2.30 - Audio compression toolkit. (...
xACT stands for X Aaudio Compression Toolkit, an application that encodes and decodes FLAC, SHN, Monkey’s Audio, TTA, Wavpack, and Apple Lossless files. It also can encode these formats to MP3, AAC... Read more
Firefox 31.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals... Read more
Little Snitch 3.3.3 - Alerts you to outg...
Little Snitch gives you control over your private outgoing data. Track background activityAs soon as your computer connects to the Internet, applications often have permission to send any... Read more
Thunderbird 31.0 - Email client from Moz...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Together 3.2 - Store and organize all of...
Together helps you organize your Mac, giving you the ability to store, edit and preview your files in a single clean, uncluttered interface. Smart storage. With simple drag-and-drop functionality,... Read more
Cyberduck 4.5 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more

Latest Forum Discussions

See All

LEX Goes Free For One Day In Honor of Ne...
LEX Goes Free For One Day In Honor of New Update Posted by Jennifer Allen on July 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Thomas Was Alone Goes Universal, Slashes...
Thomas Was Alone Goes Universal, Slashes Price to $3.99 Posted by Ellis Spice on July 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meerkatz Challenge Review
Meerkatz Challenge Review By Jennifer Allen on July 24th, 2014 Our Rating: :: FONDLY PUZZLINGUniversal App - Designed for iPhone and iPad Cute and challenging, Meerkatz Challenge is a fun puzzle game, particularly for fans of... | Read more »
Book Your Appointment with F.E.A.R. this...
Book Your Appointment with F.E.A.R. | Read more »
It Came From Canada: Epic Skater
For all the hate that it gets for being a pastime for slackers, skateboarding really does require a lot of skill. All those flips and spins take real athleticism, and there’s all the jargon to memorize. Fortunately for us less extreme individuals,... | Read more »
Cultures Review
Cultures Review By Jennifer Allen on July 24th, 2014 Our Rating: :: SLOW-PACED EMPIRE BUILDINGiPad Only App - Designed for the iPad Cute it might seem, but Cultures is a bit too slow paced when it comes to those pesky timers to... | Read more »
More Paintings Have Been Added to Paint...
More Paintings Have Been Added to Paint it Back! Posted by Jessica Fisher on July 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
The Order of Souls Review
The Order of Souls Review By Campbell Bird on July 24th, 2014 Our Rating: :: STORY GRINDUniversal App - Designed for iPhone and iPad The Order of Souls is a free-to-play, turn-based RPG with a genre-mixing art style, interesting... | Read more »
Revolution 60 Review
Revolution 60 Review By Jordan Minor on July 24th, 2014 Our Rating: :: LASS EFFECTUniversal App - Designed for iPhone and iPad Revolution 60 is a bold, cinematic action game with ambition to spare.   | Read more »
Matter (Photography)
Matter 1.0.1 Device: iOS Universal Category: Photography Price: $1.99, Version: 1.0.1 (iTunes) Description: Add stunning 3D effects to your photos with real-time shadows and reflections. Export your creations as photos or video loops... | Read more »

Price Scanner via MacPrices.net

Global Tablet Market Grows 11% in Q2/14 Notwi...
Worldwide tablet sales grew 11.0 percent year over year in the second quarter of 2014, with shipments reaching 49.3 million units according to preliminary data from the International Data Corporation... Read more
Save on 5th generation refurbished iPod touch...
The Apple Store has Apple Certified Refurbished 5th generation iPod touches available starting at $149. Apple’s one-year warranty is included with each model, and shipping is free. Many, but not all... Read more
What Should Apple’s Next MacBook Priority Be;...
Stabley Times’ Phil Moore says that after expanding its iMac lineup with a new low end model, Apple’s next Mac hardware decision will be how it wants to approach expanding its MacBook lineup as well... Read more
ArtRage For iPhone Painting App Free During C...
ArtRage for iPhone is currently being offered for free (regularly $1.99) during Comic-Con San Diego #SDCC, July 24-27, in celebration of the upcoming ArtRage 4.5 and other 64-bit versions of the... Read more
With The Apple/IBM Alliance, Is The iPad Now...
Almost since the iPad was rolled out in 2010, and especially after Apple made a 128 GB storage configuration available in 2012, there’s been debate over whether the iPad is a serious tool for... Read more
MacBook Airs on sale starting at $799, free s...
B&H Photo has the new 2014 MacBook Airs on sale for up to $100 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels... Read more
Apple 27″ Thunderbolt Display (refurbished) a...
The Apple Store has Apple Certified Refurbished 27″ Thunderbolt Displays available for $799 including free shipping. That’s $200 off the cost of new models. Read more
WaterField Designs Unveils Cycling Ride Pouch...
High end computer case and bag maker WaterField Designs of San Francisco now enters the cycling market with the introduction of the Cycling Ride Pouch – an upscale toolkit with a scratch-free iPhone... Read more
Kingston Digital Ships Large Capacity Near 1T...
Kingston Digital, Inc., the Flash memory affiliate of Kingston Technology Company, Inc.,has announced its latest addition to the SSDNow V300 series, the V310. The Kingston SSDNow V310 solid-state... Read more
Apple’s Fiscal Third Quarter Results; Record...
Apple has announced financial results for its fiscal 2014 third quarter ended June 28, 2014, racking up quarterly revenue of $37.4 billion and quarterly net profit of $7.7 billion, or $1.28 per... 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
Sr. Project Manager for *Apple* Campus 2 -...
…the design and construction of one building or building components of the New Apple Campus located in Cupertino, CA. They will provide project management oversight for Read more
WW Sales Program Manager, *Apple* Online St...
**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
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.