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

Evernote 7.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
MacUpdate Desktop 6.2.0 - $20.00
MacUpdate Desktop brings seamless 1-click app 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... Read more
HoudahSpot 4.3.5 - Advanced file-search...
HoudahSpot is a versatile desktop search tool. Use HoudahSpot to locate hard-to-find files and keep frequently used files within reach. HoudahSpot will immediately feel familiar. It works just the... Read more
EtreCheck 4.0.4 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
WhatsApp 0.2.8361 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
iClock 4.2 - Customize your menubar cloc...
iClock is a menu-bar replacement for Apple's default clock but with 100x features. Have your Apple or Google calendar in the menubar. Have the day, date, and time in different fonts and colors in the... Read more
Dashlane 5.7.0 - Password manager and se...
Dashlane is an award-winning service that revolutionizes the online experience by replacing the drudgery of everyday transactional processes with convenient, automated simplicity - in other words,... Read more
Garmin Express 6.1.2.0 - Manage your Gar...
Garmin Express is your essential tool for managing your Garmin devices. Update maps, golf courses and device software. You can even register your device. Update maps Update software Register your... Read more
Things 3.4 - Elegant personal task manag...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
SoftRAID 5.6.5 - High-quality RAID manag...
SoftRAID allows you to create and manage disk arrays to increase performance and reliability. SoftRAID allows the user to create and manage RAID 4 and 5 volumes, RAID 1+0, and RAID 1 (Mirror) and... Read more

Latest Forum Discussions

See All

Here's everything you need to know...
Alto's Odyssey is a really, really good game. If you don't believe me, you should definitely check out our review by clicking this link right here. It takes the ideas from the original Alto's Adventure, then subtly builds on them, creating... | Read more »
Alto's Odyssey (Games)
Alto's Odyssey 1.0.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.1 (iTunes) Description: Just beyond the horizon sits a majestic desert, vast and unexplored. Join Alto and his friends and set off on an endless... | Read more »
Vainglory 5v5: Everything you need to kn...
Vainglory just got bigger. [Read more] | Read more »
Check out these 5 games that are a lot l...
So you're in love with Minecraft, but you're looking for something else to play as well? You've come to the right place then, because this list is all about games that are a bit like Minecraft. Some of them, more than others. [Read more] | Read more »
Our top 5 characters from casual RPG Cre...
Creature Quest definitely lives up to its name with a host of collectible creatures based on fantasy tales and world mythologies. To celebrate Creature Quest’s first birthday, we’re going to lay out what we think are the five best characters in the... | Read more »
Around the Empire: What have you missed...
Did you know that Steel Media has a whole swathe of other sites dedicated to all aspects of mobile gaming? Sure you'll get the very best iPhone news, reviews, and opinions right here at 148Apps, but we don't want you missing out on a single piece... | Read more »
All the best games on sale for iPhone an...
Oh hi there, and welcome to our round-up of the best games that are currently on sale for iPhone and iPad. You thought I didn't see you there, did you, skulking behind the bushes? Trust me though, the bushes aren't where the best deals are. The... | Read more »
The Battle of Polytopia Guide - How to H...
A new update just released for The Battle of Polytopia (formerly Super Tribes), which introduces online multiplayer. For all the fans of Midjiwan’s lite take on Civilization, this is certainly welcome news, but playing online isn’t as easy and... | Read more »
Here are the very best mobile games to p...
It's Valentine's Day! Did you get loads of cards and chocolates and other tacky, simple expressions of human affection? Did you send out tat because you find it almost impossible to express emotion unless there's a section dedicated to it at your... | Read more »
Florence (Games)
Florence 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Florence is an interactive storybook from the award-winning lead designer of Monument Valley about the heart-racing highs and... | Read more »

Price Scanner via MacPrices.net

Lowest price of the year: 15″ 2.8GHz Apple Ma...
Amazon has the 2017 Space Gray 15″ 2.8GHz MacBook Pro on sale today for $251 off MSRP. Shipping is free: – 15″ 2.8GHz Touch Bar MacBook Pro Space Gray (MPTR2LL/A): $2148, $251 off MSRP Their price is... Read more
Apple restocks full line of Certified Refurbi...
Apple has restocked a full line of Apple Certified Refurbished 2017 13″ MacBook Pros for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
Lowest sale price available for 13″ 1.8GHz Ma...
Focus Camera has the 2017 13″ 1.8GHz/128GB Apple MacBook Air on sale today for $829 including free shipping. Their price is $170 off MSRP, and it’s the lowest price available for a current 13″... Read more
21-inch 2.3GHz iMac on sale for $999, $100 of...
B&H Photo has the 2017 21″ 2.3GHz iMac (MMQA2LL/A) in stock and on sale for $999 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. Read more
Apple refurbished Mac minis in stock again st...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Tuesday MacBook Deals: $250 off 15″ 2.9GHz Ma...
Adorama has the Silver 15″ 2.9GHz Apple MacBook Pro on sale today for $250 off MSRP. Shipping is free, and Adorama charges sales tax for residents in NY & NJ only: – 15″ 2.9GHz Silver MacBook Pro... Read more
Save up to $350 with these Apple Certified Re...
Apple has a full line of Certified Refurbished iMacs available for up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: – 27... Read more
B&H offers $200 discount on Silver 15″ Ma...
B&H Photo has Silver 15″ Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 15″ 2.8GHz Touch Bar MacBook Pro Silver (... Read more
12″ Apple iPad Pro Sale of the Year! Models u...
B&H Photo has 12″ #iPad Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad Pro: $719 $80 off MSRP – 12″ 256GB WiFi... Read more
Deals on 32GB 9″ iPads: Up to $50 off MSRP, s...
B&H Photo has 2017 9.7″ 32GB iPads on sale for $299 including free shipping plus NY & NJ sales tax only. Their price is $30 off MSRP, and it’s currently the lowest price available for these... Read more

Jobs Board

*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
Sr. Experience Designer, Today at *Apple* -...
# Sr. Experience Designer, Today at Apple Job Number: 56495251 Santa Clara Valley, California, United States Posted: 18-Jan-2018 Weekly Hours: 40.00 **Job Summary** Read more
*Apple* Technical Specialist - Apple, Inc. (...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of 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
Strategist, *Apple* Media Products, Content...
# Strategist, Apple Media Products, Content and Marketing Job Number: 113399632 Santa Clara Valley, California, United States Posted: 20-Feb-2018 Weekly Hours: 40.00 Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.