TweetFollow Us on Twitter

Designing Interface Builder Palettes

Volume Number: 19 (2003)
Issue Number: 6
Column Tag: Programming

Designing Interface Builder Palettes

Simple To Advanced Palette Design

by Ed VanVliet

Introduction

Anytime you have a reusable user interface component you should consider integrating it into Interface Builder as a palette so it is readily accessible. This article describes how to make a simple Interface Builder palette and also explains some design issues encountered for more advanced palettes via the graph palette that was implemented at VVI(R). By way of introduction, Figure 1 shows the graph palette being used in an example application project.


Figure 1: The Graph Interface Builder Palette In Use

To make such an application, launch Project Builder and make a new Application-based project. That project includes the Interface Builder nib file called MainMenu.nib. Double click that nib file from within Project Builder to open it. That nib file contains an Application Menu and Main Window by default as shown in Figure 1. Drag a new Pie Chart from the Graph Palette to the Main Window of the project, resized it accordingly and finally use the Graph View Inspector to change the pie chart to a line graph representation, as shown on the Main Window in Figure 1. Then save the project to the disk. That is all that is needed to add a basic graph to an application.

The aim of this article is to describe how easy it is to make a palette similar to that used above, to trim off a few rough edges that you will encounter when you make your own Interface Builder palette and then to describe an advanced palette design. But, before going into those details lets first complete the example application just described by adding data to it.

Completing The Graph Project

The only thing left to do in the application described above is to add your own data to the graph while the application runs. To do that, add a new controller class, called EX_Controller, to the project using File > New File > Objective-C class. Then add the ivar EX_test_view to its interface in the file EX_Controller.h and add the following code section to its implementation in the file EX_Controller.m:

- (void)awakeFromNib
{
   NSString *inputString, *stringFormat;
   NSString *mainTitle, *xTitle, *yTitle;
   unsigned chartType;
   double value1, value2, value3, value4;
/* The following define the attributes of the column chart. */
   chartType = VP_COLUMN_OUTPUT_TYPE;
   mainTitle = @"This Is My Main Title";
   xTitle = @"My X-Axis";
   yTitle = @"My Y-Data!";
/* The following data is hardcoded, but could have come from any source, such as a database 
server. */
   value1 = 100.0;
   value2 = 50.0;
   value3 = 77.0;
   value4 = 22.0;
/* The attributes and data above are formatted into a string according to the specifications in 
the documentation. */
   stringFormat = @"%@&%@&%@&%f,%f,%f,%f";
   inputString = [NSString stringWithFormat:stringFormat
      , mainTitle, xTitle, yTitle
      , value1, value2, value3, value4];
/* The following updates the view with the input string and type information, which will enable 
the graph view to update to the new graph when needed. */
   [EX_test_view VPN_update_using_input_string:inputString
      output_type:chartType];
}

The graph view definitions are maintained in the Vvidget_VP framework, so import that framework at the top of EX_Controller.m using this code:

#import <Vvidget_VP/Vvidget_VP>;

Finally, include that Vvidget_VP framework as a framework to link against in the application project.

Then double click MainMenu.nib to launch Interface Builder read in the EX_Controller class definition (Using Class > Read Files ...) , instantiate it and connect the EX_test_view outlet of that instantiation to the graph view. Then rebuild the project, launch the resulting application and see the data on the graph. Notice that a pie chart was dragged from the palette, it was changed to a line graph using the Graph View Inspector in Interface Builder and the example application changed that to a column chart when it executed. This example project and the graph palette may be downloaded at http://www.vvi.com/download/vvidgetuser.

Notice how easy it was to make the graph and how virtually no description of programming or underlying implementation was needed. The next sections correct this situation by first explaining how to make your own palette and then giving a high-level overview of the graph palette design in order to show how a large project may be handled in Interface Builder.

Making A Simple Palette

Use Project Builder to make a palette from scratch. Launch Project Builder, choose File > New Project and select Standard Apple Plug-ins > IBPalette. Then name it and save it. I saved it as the name MyIBView, so the result is a project with that name. In that project are a few premade class files and nib files as shown in Figure 2. The objective of a palette is to quickly set states of a controlled object, so the next step is to add some state information to the object controlled by the palette.


Figure 2: MyIBView Project Builder and the MyIBViewPalette Interface Builder files

There are three types of objects (Classes) in the palette, MyIBView, MyIBViewPalette and MyIBViewInspector. MyIBView is a view class and the palette is responsible for defining that class and making and modifying views (instances) of that class. A view is a rectangular area that draws in a window so the next step is to implement that functionality.

MyIBView is declared in the file MyIBView.h. That file must be modified to declare some sort of state information. The state used in this example is a background color. To add that state implement the interface of the class like this:

@interface MyIBView : NSView
{
   NSColor *backgroundColor;
}
@end

The file MyIBView.m defines the implementation of the MyIBView, and that is where view-related code that gets executed by the palette should be placed. The main thing the view does is draw a background. Drawing for a view is accomplished by the method named drawRect: so add this method:

- (void)drawRect:(NSRect)aRect
{
   [backgroundColor set];
   NSRectFill([self bounds]);
}

The view must initialize its state, which is done by this method:

- (id)initWithFrame:(NSRect)aRect
{
   [super initWithFrame:aRect];
   backgroundColor = [[NSColor redColor] retain];
   return self;
}

Because the view state will be stored in an application-related Interface Builder nib file the view must be able to store and retrieve its state using the standard Cocoa coder. The following methods do that:

- (id)initWithCoder:(NSCoder *)decoder
{
   self = [super initWithCoder:decoder];
   backgroundColor = [[decoder decodeObject] retain];
   return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
   [super encodeWithCoder:coder];
   [coder encodeObject:backgroundColor];
}

Finally, the view needs to be able to allow external objects (calling code, such as an Inspector) to set and get its state. That is accomplished by these methods:

- (void)setBackgroundColor:(NSColor *)aColor
{
   if(aColor != backgroundColor)
   {
      [backgroundColor release];
      backgroundColor = aColor;
      [self setNeedsDisplay:YES];
   }
}
- (NSColor *)backgroundColor
{
   return backgroundColor;
}

If the view gets removed then it must be able to release its resources. That is accomplished by the dealloc method:

- (void)dealloc
{
   [backgroundColor release];
   [super dealloc];
}

A view will be removed (released) if the window it is on is closed (and the window is marked to release), if it is cut from the Interface Builder window it is on, or some other condition like that so it is important to release its resources.

That is all that is needed to define the state and functionality of the view. The next step is to locate that view on the palette itself. The palette interface configuration is maintained in an Interface Builder file called MyIBViewPalette.nib. Find that file within the project and double click it and drag out a CustomView (from the Cocoa-Containers palette) onto the Palette Window. Click on that CustomView, type Apple-5 and in the resulting Custom Class Inspector find MyIBView and click it. The CustomView will now instantiate as a MyIBView instance, which means the drawRect: method and other code implemented above will be executed by the palette when it is run. Save the nib file and build the result in Project Builder. You are done making the palette, so make sure to quit Interface Builder and Project Builder.

Testing The Simple Palette With An Example Application

Using the Finder locate the palette, named MyIBView.palette, that you just built. Normally it is in the build subfolder of the palette project. Double click MyIBView.palette to launch Interface Builder and to add the palette to the list of palettes to use in Interface Builder. See the resulting red rectangle in the Palette window of Interface Builder? That is your view drawing there. You can now add it to your own applications when you want to.

To make an example application, first quit Interface Builder. Then launch Project Builder, choose File > New Project and select Application > Cocoa Application. Click Next and save it as MyApplication. MyApplication has a file called MainMenu.nib in the Resource Folder of the project. Double click that to launch Interface Builder, drag your red rectangle onto the resulting window and then save it. You cannot run it yet because, while Interface Builder can execute MyIBView through the loaded palette plug-in, MyApplication cannot because it is a completely separate program. You must first create the MyIBView class in the MyApplication project. To do that click on the Classes folder then click File > New File and choose Objective-C NSView subclass, then name it as MyIBView and click Finish. The results are two files called MyIBView.m and MyIBView.h. Add to the content of those files the same lines of code that you did for the corresponding files in the MyIBView palette project. Then build and run your application from Project Builder. When run, a window comes forward with the red rectangle defined by the MyIBView instance.

You have just made a palette and a custom application that uses that palette to do some drawing. To extend it, go back to the palette project and add additional state and implementation code. Repeat that process until you get the type of drawing you want. The next sections describe how to refine the palette a bit and then describe some of the broader issues encountered in a more advanced palette implementation.

Adding An Attribute Inspector To The Simple Palette

Notice that the view of class MyIBView in Interface Builder has no Attributes Inspector. That is because you did not add any controls to the inspector in the MyIBView palette project. To do that launch your MyIBView project, go to the Resources folder and double click the file named MyIBViewInspector.nib to launch Interface Builder. Within the Class tab follow the class hierarchy to IBInspector where you will find something like this:

NSObject > IBInspector > _ROJECTNAMEASIDENTIFIERIjinspector

You need to change the last part to MyIBViewInspector to make things work, obviously a small template parsing problem while making new IB palettes (This bug is in version 2.3 of Interface Builder and may be fixed in later versions). Then click on the Instance tab, click on the File's Owner and in the Custom Class inspector click MyIBViewInspector. Now you will be able to make connections, add new outlets and actions, etc. to the File's Owner.

The palette controls the view of class MyIBView. That view has a background color as its only added attribute. So, a likely improvement is to add a control that modifies color. To do that drag a color well onto the Inspector Window, control drag from that color well to the File's Owner and then connect the color well's target outlet to the ok: action of the File's Owner. Then save the nib file and quit Interface Builder. In MyIBViewInspector.m modify this code:

- (void)ok:(id)sender
{
   /* Your code Here */
      [super ok:sender];
}
to this:
- (void)ok:(id)sender
{
   id myView = [self object];
   [myView setBackgroundColor:[sender color]];
   [super ok:sender];
}

The color well's action is the ok: method which, by the implementation above, will modify the background color of the view. Everything is done so rebuild the MyIBView project. Next, launch your MyApplication project, double click MainMenu.nib to launch Interface Builder again (this time it loads with the new inspector), click on your red view and type Apple-1 to bring forward the Attributes inspector. This time it has a color well on it. Click on the color well frame to bring forward the color panel. Change the color and watch the color attribute change in the color well and, because the target of the well is the ok: method, which forwards the action to your view, your view's background color also changes.

You have built a palette, made an example application using that palette and extended the palette to permit a state change of your own view within Interface Builder. That is a pretty good start, but a lot of improvements and design issues have yet to be touched upon. The next sections outline some of those issues.

Some Problems With The Simple Palette

The simple palette has already come a long way and it is a good starting point, but there are quite a few problems with it, some of which are listed here:

  • The declaration and definition of MyIBView are maintained in two places. They are in the palette project and separately in the example application project and for every new project that uses that view class they have to be placed there too. That can cause a code maintenance issue. To solve this problem you can make a third project which is a framework and move the declaration and definition of MyIBView to that framework and then link the palette, the example application and any future projects to that framework.

  • The implementation of the ok: method assumes the sender is a color well. That is problematic because if the inspector is updated to have two controls then the sender can be either one of the controls. There are a few ways around this issue, the easiest is to assign each control to an ivar of the inspector and then to test which ivar the sender is. The other option is to make additional action methods and make each one of those a target of only one control, such as this:

- (void)changeBackgroundColor:(id)sender
{
   id myView = [self object];
   [myView setBackgroundColor:[sender color]];
   [super ok:sender];
}
  • If you add new states to MyIBView and implement their store in the coding methods then MyApplication project will stop working. That is because the states were previously stored in the MainMenu.nib file as defined by the old version of the coding methods which are inconsistent with the new version of the coding methods. The state coding methods shown above rely on the old-style coding where the implementer needs to manage versioning manually. The newer key-value type archiving solves this problem to some extent. This issue is easily dealt with, but it is something that needs to be kept in mind while iterating a palette design. The easiest solution is to iterate the palette design to a final product without making an example project, release the palette at that version and then deal with versioning issues in a future release, but not necessarily while iterating the design of the palette.

  • Many non-essential details, such as declaring the method prototypes in header files and implementing attribute loading code in the inspector have not been shown here and are left to the reader to implement.

    Other than that, the simple palette project is ready to be extended by adding more state variables (ivars), attribute set and get methods, coding additional states, adding more controls to the inspector and, finally, because it's all about drawing, to use that state information for drawing in the view's rectangular region.

    Design Of The Graph Palette

    The example palette described above is a handful of lines long, pretty small. But what happens when the attributes, features and code grows? How does the paradigm scale and how would it need to be changed to accommodate scale-dependent issues when the code base approaches a million lines of code? The programming environment on Mac OS X permits an arbitrary amount of code to be loaded into Interface Builder as Frameworks and Bundles so conceivably anything can be inserted into Interface Builder. Early on one of our palette implementations loaded all of our frameworks, initialized our whole environment and gave access to attributes that were many times greater than all of those available in Interface Builder by default. The system depended on running two independent document and inspector systems in parallel. It worked reasonable well, but suffered from a major design flaw: it gave the ultimate flexibility to solve a vast amount of problems, but did not solve the pertinent problem well. That is because users of the palette typically did not ask "how can I adjust that attribute?", rather they ask: "how can I get a line plot" or similar final result.

    After many other design attempts a client server implementation was chosen. That system, called the Peer Visual(TM) Server, is diagrammed in Figure 3. The server is capable of handling about 1000 simultaneous requests. Some are transitory such as requests from web browsers and some are dedicated like requests from an Interface Builder view. For each graph dragged from the palette to the application windows, such as in Figure 1, a new dedicated connection is made. The connections are load balanced amongst several servers (2 by default) and delegated to different threads within the servers. The multi-process, threaded and parallel nature of the implementation means that a multi-CPU computer is used to its fullest extent by the Interface Builder views. The other major benefit to this design is that the client applications do not have to load in the frameworks that make the graphs because they reside in another process space.


    Figure 3: Peer Visual Server And The Interface Builder Palette

    The design also incorporates a server monitor that starts the servers on demand, checks for valid connections, rolls over servers in the case of an error, and in the unlikely event that generating a graph encounters a terminal error the Monitor restarts a server for a client. This gives added protection to applications using this system, i.e.: an error on the server side will not terminate the client side process. This also has a good programming benefit in that there are no namespace, process address space, or run time resource conflicts between the client and the server.

    The server is fully programmable, extensible and has access to all the attributes of the frameworks it depends on. That means the server can be extended to make nearly any type of report or graphic and access any database or other data source all while maintaining the infrastructure of the client server model and Interface Builder implementation, so that conceivably all output of the frameworks can be inserted into Interface Builder without the problematic issues encountered in the earlier homogeneous implementation mentioned above.

    The graph palette was made in the same way as the Simple Palette described above, except that the state information is not a background color, but rather an input string, chart type and a Peer Visual Server connection. Other than that, the two palette implementations are basically the same.

    The other advantage to the graph palette implementation is that the client may be a Cocoa, Java, Carbon or other type of implementation while the Peer Visual Server can maintain its own implementation criterion. You can find an example of this heterogeneous use at www.marketocracy.com where visual formats from the Peer Visual Server help members manage very successful mutual funds like the fund shown in Figure 4.


    Figure 4: Output Of Custom Peer Visual Server From www.marketocracy.com (Courtesy of Marketocracy(R), Inc).

    In this case, the Peer Visual Server outputs its results to a web browser, but because of the client server architecture that same Peer Visual Server can be used to make a desktop application without any alteration of the server code. The design is also used to off-load the data query, modeling computation and resulting visualization portion of the display to a separate computer so that it enables the Interface Builder palette to incorporate distributed computing. In addition, the graphical layout of the output is maintained in a separate coded state maintained by a widget builder called Vvidget Builder(TM) which is designed to handle data-related diagramming and graphs (the figures for this article were made with Vvidget Builder). In that way, the graph state and function is partitioned from the Interface Builder palette implementation so, for example, it does not suffer from the versioning problem described above.

    Conclusion

    For simple functionality, such as a dial or simple control with few attributes the normal Interface Builder plug-in model may be sufficient. But that model suffers from many ills found in homogeneous software architectures. Those ills were mentioned in previous sections and are fundamental to large-scale processing and software design and are not unique to Interface Builder. The client server architecture of the Peer Visual Server addressed those ills in a straight forward way and broadens the applicability of the implementation by permitting reuse of the system with the Interface Builder graph palette as well as different client environments such as Cocoa, Carbon and Java and different client interfaces from desktop applications to web browsers. In that sense, Interface Builder is not a tool to solve all problems, but rather a tool that permits easy access to heterogeneous systems from within a desktop application through palette extensions. So, it is the recognition of that applicability of the Interface Builder palette paradigm that is the main point of this article.

    References

    You can download the graph palette and supporting code, example project, documentation, graphing server, Vvidget Builder layout application and other resources at http://www.vvi.com/download/vvidgetuser. You can also get one million dollars, professional fund-managment tools with great looking reports and graphs and have the opportunity to become a very successful mutual fund manager at www.marketocracy.com. The dollars are virtual, but the underlying software and results are not.

    Legal

    VVI is a Registered Trademark of VVimaging, Inc. VVI, Vvidget, Vvidget Builder, Vvidget User, Peer Visual and VVimaging are trademarks of VVimaging, Inc. in the United States and world-wide. Marketocracy is a Registered Trademark of Marketocracy, Inc. References to Marketocracy are for informational purposes only.


    Ed VanVliet is Director Of Application Development at VVI where he helps design and construct business and engineering data systems. He designed the Peer Visual Server as well as interfaces to database systems, instrumentation and real-time data feeds and is currently working on a variety of systems and conversions between Windows and Mac OS X for business and engineering companies. You can contact him at ed@vvi.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Tunnelblick 3.7.4b - GUI for OpenVPN.
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more
Carbon Copy Cloner 5.0.5 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
Postbox 5.0.22 - Powerful and flexible e...
Postbox is a new email application that helps you organize your work life and get stuff done. It has all the elegance and simplicity of Apple Mail, but with more power and flexibility to manage even... Read more
Ortelius 2.0.8 - Vector drawing app espe...
Ortelius is a full-featured vector drawing application especially for map design. Draw directly with features such as roads, rivers, coastlines, buildings, symbols and contours. Ortelius is known for... Read more
Bartender 3.0.32 - Organize your menu-ba...
Bartender lets you organize your menu-bar apps by hiding them, rearranging them, or moving them to Bartender's Bar. You can display the full menu bar, set options to have menu-bar items show in the... Read more
Adobe Animate CC 2018 18.0.1.115 - Anima...
Animate CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate CC 2018 (was Flash CC) lets you... Read more
Adobe Lightroom Classic CC 7.1 - Import,...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
ExpanDrive 6.1.8 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
ExpanDrive 6.1.8 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
DiskCatalogMaker 7.2.7 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more

Latest Forum Discussions

See All

The best deals on the App Store this wee...
A new week means new discounts on the App Store. This week's deals run the gamut of action-adventure titles, puzzle games, and one of the best narrative adventure series out there. If you're looking to fill out your mobile gaming library on a... | Read more »
What you need to know about Animal Cross...
We hope you've been hard at work on collecting all of those holiday items in Animal Crossing: Pocket Camp, because you're about to get a whole new list of fun things to do as the game receives its first big update sometime soon. There are a lot of... | Read more »
Reigns: Her Majesty guide - how to use e...
Ruling a kingdom isn't easy--doubly so for a queen whose every decision is questioned by the other factions seeking a slice of power. Reigns: Her Majesty builds on the original game's swipey tactics, adding items that you can use to move the story... | Read more »
The best new games we played this week -...
Friday has crept up on us once again, so it's time to honor the best new games we've played over the past few days. This past week was a pretty exciting one, with the debut of lots of beautiful new indies and some familiar faces returning to the... | Read more »
Portal Knights guide- beginner tips and...
Portal Knights is finally making the jump to iOS and Android, and it's already climbing the ranks to become the next big MMO experience on mobile. This sprawling sandbox game will let you pursue any adventure you wish, whether you want to sling... | Read more »
Reigns: Her Majesty guide - how to swipe...
Reigns: Her Majesty is storming the App Store this week, bringing more tinder-esque kingdom building to eager players everywhere. If you've played the original Reigns, you'll know that leading a kingdom is never easy. It's a careful balancing act... | Read more »
Getting Over It (Games)
Getting Over It 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: A game I madeFor a certain kind of person To hurt them. • Climb up an enormous mountain with nothing but a hammer and a pot.•... | Read more »
Reigns: Her Majesty (Games)
Reigns: Her Majesty 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Pocket Legends Adventures guide - how to...
Pocket Legends Adventures is a fun action adventure RPG that takes control when you want it to, but also opens itself for player input, too, if you're looking to tkae a more active role in combat. Regardless of play style, the game can be quite... | Read more »
Portal Knights (Games)
Portal Knights 1.2.4 Device: iOS Universal Category: Games Price: $4.99, Version: 1.2.4 (iTunes) Description: Craft your adventure. Forge your hero. Become the ultimate Portal Knight! | Read more »

Price Scanner via MacPrices.net

Apple Watch Series 2, Certified Refurbished,...
Apple has Certified Refurbished Apple Watch Nike+ Series 2s, 42mm Space Gray Aluminum Case with Anthracite/Black Nike Sport Bands, available for $249 (38mm) or $279 (42mm). The 38mm model was out of... Read more
Apple offers Certified Refurbished 2016 12″ R...
Apple has Certified Refurbished 2016 12″ Retina MacBooks available starting at $949. Apple will include a standard one-year warranty with each MacBook, and shipping is free. The following... Read more
B&H drops price on 13″ 256GB MacBook Air...
B&H has the 13″ 1.8GHz/256GB Apple MacBook Air (MQD42LL/A) now on sale for $1079 including free shipping plus NY & NJ sales tax only. Their price is $120 off MSRP, and it’s the lowest price... Read more
Holiday sale: 9″ iPads starting at $299, take...
MacMall has 9″ WiFi iPads on sale for $30 off including free shipping: – 9″ 32GB WiFi iPad: $299 – 9″ 128GB WiFi iPad: $399 Read more
Green Monday deal: 15″ 2.8GHz MacBook Pro on...
B&H Photo has the 15″ 2.8GHz Space Gray MacBook Pro on sale for $250 off MSRP for today only as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax for NY... Read more
Green Monday sale: B&H offers 12″ Apple i...
B&H Photo has 12″ iPad Pros on sale for up to $150 off MSRP as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad... Read more
Holiday deal: 21″ and 27″ Apple iMacs on sale...
MacMall has 2017 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP. Shipping is free: – 21″ 2.3GHz iMac: $999 $100 off MSRP – 21″ 3.0GHz iMac: $1199 $100 off MSRP – 21″ 3.4GHz iMac: $1379 $120... Read more
Holiday deal: Apple Mac minis for up to $150...
MacMall has Mac minis on sale for up to $100 off MSRP, each including free shipping: – 1.4GHz Mac mini: $399 $100 off MSRP – 2.6GHz Mac mini: $599 $100 off MSRP – 2.8GHz Mac mini: $949 $50 off MSRP... Read more
Beats by Dr. Dre – BeatsX Earphones on sale f...
Best Buy has BeatsX Earphones on sale for $109, $40 off, on their online store. Sale price for online orders only. Choose free store pickup, if available, or choose free shipping. Read more
10″ 64GB WiFi Apple iPad Pros on sale for $59...
MacMall has 10.5″ 64GB Apple iPad Pros on sale for $599 including free shipping. That’s $50 off MSRP and among the lowest prices available for these iPads from any Apple reseller. Read more

Jobs Board

QA Automation Engineer, *Apple* Pay - Apple...
# QA Automation Engineer, Apple Pay Job Number: 113202642 Santa Clara Valley, California, United States Posted: 11-Dec-2017 Weekly Hours: 40.00 **Job Summary** At Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Information Security - Security Data...
# Apple Information Security - Security Data Analyst Job Number: 113119545 Austin, Texas, United States Posted: 10-Nov-2017 Weekly Hours: 40.00 **Job Summary** This Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.