TweetFollow Us on Twitter

The Road to Code: Writing Even Less Code

Volume Number: 24
Issue Number: 12
Column Tag: The Road to Code

The Road to Code: Writing Even Less Code

Introduction to Core Data

by Dave Dribin

Core Data

Our topic this month is Core Data, a technology introduced in Mac OS X 10.4 by Apple to help reduce time spent writing code. Interface Builder allows you to setup view classes with out writing any custom layout code. Cocoa bindings allow you tie together the view and the model without writing any custom controller code. What's left? The model. Core Data is an attempt to allow developers to write model classes without writing any code.

Core Data was introduced in Mac OS X 10.4 and heavily enhanced in OS X 10.5. In a nutshell, Core Data provides automatic object persistence and object lifecycle management. The phrase object persistence is a fancy way of saying "saving objects to a file," similar to archiving. Core Data provides more, though. It allows you to find and filter objects and provides integration with the user interface, such as automatic undo support. It can optionally store your objects to a single-user relational database for increased performance.

It is common to think of Core Data as an object-relational mapping (ORM) tool. ORM tools automatically persist objects to a relational database. ORM tools allow you to save, find, and update objects using SQL statements. SQL is the language of relational databases, and ORM tools typically generate the SQL select, update and insert statements for you. Some popular ORM tools in the Java world are Hibernate and Enterprise Java Beans (EJB), and Active Record is the ORM tool for Ruby on Rails.

However, there is one very important difference between most ORM tools and Core Data. Most ORM tools are designed for multi-user and high-concurrency environments, such as the backend of web application. Core Data is designed with the single-user desktop application in mind. You'll see some of the ramifications of this as you delve into the architecture and use cases of Core Data. For example, Core Data does not require use of a relational database.

A Bit of History

Before digging into the details of Core Data, it is useful to understand where it came from. It turns out that Apple has it's own web-based ORM tool as part of WebObjects. WebObjects is a complete web application framework. It started life way back in the early 1990s at NeXT written in Objective-C and was later rewritten in Java. When Apple acquired NeXT, mainly for Mac OS X, it also acquired WebObjects. Today, Apple uses WebObjects for its online store and the server side components of the iTunes Music Store. It is also available for free for developers to use and has quite a strong, albeit small, following.

WebObjects includes an ORM tool called Enterprise Objects Frameworks, or EOF. It allows automatic persistence of Java model objects to a relational database. As far as ORM tools go, EOF is quite powerful and feature filled. However, since it is now only available in Java, it is not something that can be used directly by Cocoa applications.

Apple used its experience with EOF to design Core Data. It took many of the concepts of EOF and pared them down for single-user applications. There is no direct link between EOF and Core Data, just a foundation of ORM experience. Unfortunately, not all of the features of EOF were ported to Core Data, so sometimes we are left wanting.

Terminology

Core Data introduces some new terminology, mainly borrowed terminology from the database world. Databases are modeled using the entity-relationship model, thus Core Data objects are also modeled using the entity-relationship model. But don't fret, most of these terms correlate to terms you already know.

In an entity-relationship model, a class is called an entity. And just classes contains instance variables, entities contain properties. There are two kinds of properties: attributes and relationships. Attributes are properties consisting of simple data types, such as strings, numbers, and dates. Relationships are properties that link together multiple entities. We won't be covering relationships in this article.

Okay, enough of the jibber jabber, let's get on to writing a Core Data application.

Core Data Version of Rectangles

We are going to convert the Rectangles application that we have built up over the last few months to a Core Data application. Using Core Data will allow us to remove almost all of our code. We can't quite get rid of all of it, but the reduction is still dramatic.

We're going to start off my creating a new project. Create a Core Data Document-based Application from the New Project window, as shown in Figure 1.


Figure 1: New Core Data project

This project looks similar to standard document-based applications, but it has an additional group in the Groups & Files list called Models, as shown in Figure 2. In that group is a file named MyDocument.xcdatamodel. This file extension is short for "Core Data data model" and represents the entity-relationship model for our application.


Figure 2: Groups and Files

We're going to dive right in by working on our data model first. We want to create a rectangle entity with width and height attributes. If you double click on the data model, you will be presented with what is known as the Core Data modeler, as shown in Figure 3. We will design our data model graphically without writing any code or text.


Figure 3: Core Data modeler

Click the + button in the Entity pane to create a new entity. Use the detail view on the right side of the window to rename the entity to Rectangle, as shown in Figure 4.


Figure 4: Rectangle entity

Next, add a new attribute by making sure the Rectangle entity is still selected and click the + button in the Property pane. Rename the attribute to width, uncheck the Optional checkbox, change the Type to Float, and set the Default Value to 0. Now repeat this process to create a height attribute. The result should look like Figure 5.


Figure 5: Height and width attributes

In the bottom half of the window, you will see a graphical representation of our entity-relationship model, as shown in Figure 6. This graphical representation is called an entity-relationship diagram or ER diagram. It is common to model relational databases using an ER diagram, again showing the database roots of Core Data.


Figure 6: Rectangle ER diagram

With that, we're done with our data model. We can now save, load, and use Rectangle entities in our application. But, we haven't written any code, yet. How can you use an entity without any code? Core Data provides built-in classes to make this easy.

Core Data Class Architecture

When you created the Rectangle entity, you'll notice that one of the fields is named Class and, by default, is set to NSManagedObject. Every instance of a Core Data entity is represented by an instance of NSManagedObject. In a way, it is similar to how NSObject is the root class of all Objective-C classes. However, you do not need to subclass NSManagedObject to use it. So how do you access the properties? Using key-value coding.

When an NSManagedObject, or managed object for short, gets instantiated, it's initialized for a particular entity. The managed object reads your data model and allows you to access the attributes using the standard KVC valueForKey: and setValue:forKey: methods. For example, say we have an instance of NSManagedObject representing our Rectangle entity. You would access the width attribute like:

    NSManagedObject * rectangle = ...;
    NSNumber * width = [rectangle valueForKey:@"width"];
    NSLog(@"Width is: %f", [width floatValue]);

But for now, we do not need to use our entity from code. We will be using Cocoa bindings to connect managed objects to the user interface, which uses KVC.

Another important class in the Core Data architecture is NSMangedObjectContext, or managed object context. You use the managed object context to find, create, and delete managed objects. Every managed object instance is owned by the managed object context that created it. The managed object context also contains unsaved changes. Thus, when the user makes their edits, these changes occur only the managed object context. To save these changes to disk, you tell the managed object context to save.

The final important class in the Core Data architecture is NSPersistentStoreCoordinator, or persistent store coordinator. A persistent store coordinator links a managed object context to a specific file on disk, called a persistent store. There are three types of persistent stores that defines the internal file format on disk: XML, binary, and SQLite. The XML persistent store is nice because you can use any text editor to examine the contents. The binary persistent store is faster and more efficient, but it is a proprietary file format. The SQLite persistent store type is the most interesting.

SQLite is a full relational database system that is self-contained and serverless. Most relational database systems, like PostgreSQL, MySQL, or Oracle, require a separate server process to run in the background. A server-based relational database requires a lot of extra setup and can be a little difficult to maintain. SQLite on the other hand is linked in as part of your application and the database is stored in a single file on disk. You access the data using standard SQL queries. SQLite cannot handle highly concurrent multi-user applications like busy web applications, but it is perfect for a single user application, like an OS X application.

When Core Data uses a SQLite persistent store, it works very much like traditional ORM tools. It generates SQL statements to create, save, and find objects in the database. Core Data does not allow you to interact with SQLite directly, though. It hides all the SQL from the programmer.

The benefit of using a SQLite persistent store type is that it is much more efficient than the XML and binary types. Only the objects that you are using get loaded into memory. Thus if the user's data contains a large amount of entities, SQLite will only load the objects the user is using, saving memory. Also, finding and filtering managed objects are more efficient since Core Data can use SQL to find the objects. Databases are designed to perform searches very efficiently.

Generally, you use the XML persistent store type during the early stages of development, because the file can be read with a text editor. However, SQLite is often the best case for a released application since it is more efficient. There are some subtle differences between the persistent store types, so if you do change persistent store types, be sure to thoroughly test after the changes. Also, if you change the type, your application will not be able to load previously saved files.

I admit that the Core Data architecture is somewhat complex. However, if you are writing a document-based application, your life is simplified. Apple provides an NSDocument subclass for document-based applications that use Core Data called NSPersistentDocument. The NSPersistentDocument takes care of setting up the persistent store coordinator and managed object context for you. When you save your document, it saves the context to the user's file. Since we chose a Core Data Document-based Application, our MyDocument class is automatically a NSPersistentDocument.

Configuring the Document Type

Let's now setup the document type for our application, so we can save and open files. Double-click on the Rectangles target to open the Info window for this target. You'll notice there are three document types already present, one for each of the different persistent store types. We'll use SQL type, so delete the other two. Change the Name to Rectangles Document and the extension to rectanglescd. We already used the rectangles extension in our previous, non-Core Data application, so we want to choose a different one to avoid a conflict.

Also change the Identifier to something unique. All of these changes are summarized in Figure 7.


Figure 7: Document types

Laying out the User Interface

We're now going to switch to Interface Builder to layout the interface and setup our Cocoa bindings. Remove the initial text label, and add a table view. Rename the columns to Width and Height. Drag number formatters on each of the columns and set their Style to Decimal. Now add two buttons underneath the table, one named Add the other named Remove. Setup the autosizing appropriately. The final result should look like Figure 8.


Figure 8: Initial window layout

Next, we're going to create an array controller for our Cocoa bindings. Drag an array controller from the Library to our xib document window, and rename it to Rectangles, as shown in Figure 9.


Figure 9: Array controller

Now setup the array controller's attributes to match Figure 10. You need to set the Mode to Entity, set the Entity Name to Rectangle, and check the Prepares Content checkbox. This puts the array controller into Core Data mode and will hold instances of NSManagedObject of the given entity name.


Figure 10: Array controller attributes

Our array controller needs a managed object context to fetch and edit managed objects. Remember that NSPersistentDocument sets up a context for each document. The File's Owner for the MyDocument.xib is our MyDocument subclass of NSPersistenDocument. We can bind the array controller's Managed Object Context to the managedObjectContext of File's Owner, as shown in Figure 11.


Figure 11: Array controller bindings

With our array controller in place, we can now bind the Width and Height columns. Just as we did for our non-Core Data application, bind the Width column to the Rectangles array controller. Set the Controller Key to arrangedObjects and the Model Key Path to width, as shown in Figure 12. Make similar bindings for the Height column, except using height as the Model Key Path.


Figure 12: Width column bindings

Finally, hookup the Add button to the Rectangles array controller's add: action and the Remove button to the remove: action. Bind the Add button's Enabled binding to the canAdd Controller Key and bind the Remove button's Enabled binding to the canRemove Controller Key.

At this point, we have a fully functional application. You should be able to add and remove rectangles from the table using the buttons, and you should be able to save and open documents. Furthermore, you will notice that you get dirty document and undo support. Now I'd like to remind you again that we haven't written any code. This is the promise of Core Data.

Of course our application is missing a few things from our non-Core Data version. First, the default width for new rectangles was 15 and the default height was 10. In our non-Core Data version, we created our own subclass of array controller and overrode the newObject method. We can certainly do that, but for now, I'm going to just change the default values in the data model, to keep with the "no code" theme.

The other major part missing is the area and perimeter table columns. Unfortunately, we are going to have to create some code to get these working. Because these are computed properties, we cannot add them in the data model. We're going to have to create a subclass of NSManagedObject for our Rectangle entity. Fortunately, Xcode can give us a head start. Make sure that your data model is selected in the Groups & Files list and click on File > New FileÉ to create a new file. Click on Managed Object Class in the New File window, as shown in Figure 13.


Figure 13: Generate managed object

Click Next as the Location and Target defaults should be correct. In the final screen, make sure that the Rectangles entity is selected as shown in Figure 14 and click Finish. This will create Rectangle.h and Rectangle.m files. You may want to move them in the Models group along with your data model file so you remember that they are managed objects.


Figure 14: Generate Rectangle class

If you look at the header, you'll see just a couple of @property declarations. There are no instance variables. Remember that the values are actually stored by the NSMangedObject superclass using KVC, so we don't need any instance variables in our subclass. These properties provide convenient, type-safe access to the entity's properties. The implementation file uses the @dynamic property keyword instead of the @synthesize. This is again because there are no instance variables.

Note that the width and height are of type NSNumber, even though we set them as Float in the data model. Core Data only deals with objects. If you want to get the actual float value, you need to use the floatValue method of NSNumber. Conversely, if you want to set the float value, you need wrap a float in an NSNumber:

    // Get the width as a float
    float width = [rectangle.width floatValue];
    // Set the width from a float
    rectangle.width = [NSNumber numberWithFloat:30.0];

Now that we have a real class, we can add our area and perimeter properties. Just as in our non-Core Data application, they are read-only. Listing 1 shows the full header with the property declarations:

Listing 1: Rectangle.h

#import <CoreData/CoreData.h>
@interface Rectangle :  NSManagedObject  
{
}
@property (retain) NSNumber * width;
@property (retain) NSNumber * height;
@property (readonly) float area;
@property (readonly) float perimeter;
@end

I used float here because it is easier to deal with primitive types when doing math. The implementation of these properties is similar to our non-Core Data application. We do have to convert the width and height to floats so we can perform math on them, though. The key-value observing methods are the same, however. Listing 2 shows the full implementation file.

Listing 2: Rectangle.m

#import "Rectangle.h"
@implementation Rectangle 
@dynamic width;
@dynamic height;
- (float)area
{
    return ([self.width floatValue] *
            [self.height floatValue]);
}
+ (NSSet *)keyPathsForValuesAffectingArea
{   
    return [NSSet setWithObjects:@"width", @"height", nil];
}
- (float)perimeter
{
    return ((2*[self.width floatValue]) +
             (2*[self.height floatValue]));
}
+ (NSSet *)keyPathsForValuesAffectingPerimeter
{
    return [NSSet setWithObjects:@"width", @"height", nil];
}
@end

And that's all the code we need. Now, we just need to add the remaining elements to the user interface.

Creating the Final User Interface

Switch to Interface Builder to complete the changes. Add two more columns to the table view and label them Area and Perimeter, respectively. Make sure they are marked as uneditable and add Decimal number formatters to both. Bind them to arrangedObjects.area and arrangedObjects.perimeter, respectively, of the Rectangles array controller. Figure 15 shows the bindings for the Area column.


Figure 15: Area column bindings

Add four labels at the bottom left side of the table for the Total Area: and Total Perimeter: fields. Two will be used for static text and two will be used for the actual values. For the two used for the values, add Decimal number formatters. The final window layout should look like Figure 16.


Figure 16: Final window layout

We are now going to setup the bindings using collection operators, just like we did in the non-Core Data application. Bind the total area value label to the Rectangles array controller. Set Controller Key to arrangedObjects and the Model Key Path to @sum.area. The result should look like Figure 17. Next, bind the total perimeter value field to the @sum.perimeter Model Key Path.


Figure 17: Total area bindings

We are now finished with our changes. You should be able to run the application and have the area and perimeter user interface elements work appropriately. Our application is nearly identical to our non-Core Data application, and all we had to do was write four methods for the area and perimeter. And this includes support for undo! Not to shabby.

Caveat Emptor

There is one subtle difference from our non-Core Data application. In our previous application, we store an array of rectangles in the document. This means that as we added rectangles, their order is preserved. Core Data uses sets, instead of arrays, which means they are unordered. But surely they have to show up in some order in the table. Unordered just means the order is not consistent. The list of rectangles may show up in a different order every time you load the file. Since the user can sort the table by clicking on one of the table columns, the easy way to fix the problem is to always sort the table by a column, by default. To truly remember the order of the items as they were entered is a very difficult Core Data problem, though. And even though setting up default column sorting is significantly easier, it is still beyond the scope of this article. For now, we'll just have to deal with that limitation.

Also, this article just scratches the tip of the Core Data iceberg. There are many more advanced topics, such a relationship properties, threading techniques, and migration between different versions of your model. Apple's documentation has a lot of information on these topics.

Conclusion

Even though Core Data is a complicated subject with some limitations, it is still a hugely valuable asset to Mac OS X development. It can save you from writing a lot of your own model code, just as Cocoa bindings can save you from writing a lot of controller code. It won't eliminate code completely, but I urge you to at least investigate Core Data for your future applications.


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/.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Apple Pro Video Formats 2.0.1 - Updates...
Apple Pro Video Formats brings updates to Apple's professional-level codes for Final Cut Pro X, Motion 5, and Compressor 4. Version 2.0.1: Support for the following professional video codecs Apple... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
EtreCheck 2.2 - For troubleshooting your...
EtreCheck is a simple little app to display 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... Read more
OmniOutliner Pro 4.2 - Pro version of th...
OmniOutliner Pro is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
VLC Media Player 2.2.1 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Nisus Writer Pro 2.1.1 - Multilingual wo...
Nisus Writer Pro is a powerful multilingual word processor, similar to its entry level products, but brings new features such as table of contents, indexing, bookmarks, widow and orphan control,... Read more
Tinderbox 6.2.0 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
OmniOutliner 4.2 - Organize your ideas,...
OmniOutliner is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
calibre 2.25.0 - Complete e-library mana...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Things 2.5.4 - Elegant personal task man...
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

Lifeline... (Games)
Lifeline... 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Lifeline is a playable, branching story of survival against all odds. Using your iPhone, iPad, or Apple Watch, you will help... | Read more »
Pandemic: The Board Game Has Gone Univer...
Don't let the virus win! Now you can download Pandemic: The Board Game, by F2Z Digital Media, for all of your iOS devices. The app is based on the fantastic board game by Z-man games. As employees of the CDC, you and your friends will have to work... | Read more »
Get Ready to Read Bloomberg Business on...
Fans of Bloomberg Business will soon be able to get all their news on the Apple Watch. The app lets you get the top headlines on your main screen and bookmark stories to read later. Using the motion detection in the Apple Watch, the headlines are... | Read more »
Watch This Homerun is Batting for the Ap...
Eyes Wide Games' Watch This Homerun is purportedly the first sports game coming to the Apple Watch, where you'll be up to bat as the pitcher tries to out-manuever you with fastballs, curveballs, and changeups. Using one-touch controls you can try to... | Read more »
Field Trip Can Take You on a Guided Tour...
Field Trip, by Google’s Niantic Labs, is an exploration app that gives you details about the awesome places you can discover wherever you find yourself. The app can show you local history, delicious restraunts, the best places to shop, and places to... | Read more »
Watch Your Six - SPY_WATCH is Infiltrati...
SPY_WATCH, by Bossa Studios, is a new game designed for the Apple Watch. Runmor has it your spy agency has fallen out of favor. To save it, you'll need to train-up a spy and send them on missions to earn you a stunningly suspicious reputation and... | Read more »
Both Halo: Spartan Assault and Halo: Spa...
Halo: Spartan Assault and Halo: Spartan Strike, by Microsoft, have officially landed on the App Store. Spartan Assault pits you against the Covenant with missions geared to tell the story of the origin of Spartan Ops. In Spartan Strike you'll delve... | Read more »
The Apple Watch Could Revolutionize the...
It’s not here yet but there’s that developing sneaky feeling that the Apple Watch, despite its price tag and low battery life, might yet change quite a lot about how we conduct our lives. While I don’t think it’s going to be an overnight... | Read more »
Mad Skills Motocross 2 Version 2.0 is He...
Mad Skills Motocross 2 fans got some good news this week as Turborilla has given the game its biggest update yet. Now you'll have access to Versus mode where you can compete against your friends in timed challenges. Turborilla has implemented a... | Read more »
Kids Can Practice Healthy Living With Gr...
Bobaka is releasing a new interactive book called Green Riding Hood  in May. The app teaches kids about yoga and organic style of life through mini-games and a fun take on the classic Little Red Riding Hood fairy tale. | Read more »

Price Scanner via MacPrices.net

Sale! 15-inch Retina MacBook Pros for up to $...
 MacMall has 15″ Retina MacBook Pros on sale for up to $255 off MSRP. Shipping is free: - 15″ 2.2GHz Retina MacBook Pro: $1794.99 save $205 - 15″ 2.5GHz Retina MacBook Pro: $2244.99 save $255 Adorama... Read more
New 2015 MacBook Airs on sale for up to $75 o...
Save up to $75 on the purchase of a new 2015 13″ or 11″ 1.6GHz MacBook Air at the following resellers. Shipping is free with each model: 11" 128GB MSRP $899 11" 256GB... Read more
Clearance 13-inch Retina MacBook Pros availab...
B&H Photo has leftover 2014 13″ Retina MacBook Pros on sale for up to $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.6GHz/128GB Retina MacBook Pro: $1129... Read more
Clearance 2014 MacBook Airs available startin...
B&H Photo has clearance 2014 MacBook Airs available for up to $200 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $729 $170 off original MSRP... Read more
16GB iPad mini 3 on sale for $349, save $50
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $349 including free shipping plus NY sales tax only. Their price is $50 off MSRP, and it’s the lowest price available for this model. Read more
Mac minis on sale for up to $75 off, starting...
MacMall has Mac minis on sale for up to $75 off MSRP including free shipping. Their prices are the lowest available for these models from any reseller: - 1.4GHz Mac mini: $459.99 $40 off - 2.6GHz Mac... Read more
Taichi Temple First Tai Chi Motion Sensor App...
Zhen Wu LLC has announced the official launch of Taichi Temple 1.0, the first motion sensor app for Tai Chi, offering a revolutionary new way to de-compress, relax and exercise all at the same time.... Read more
CleanExit – Erase your Hard Drive Quickly, Se...
CleanExit works on both Macs and PCs, securely and permanently deleting all files from any type of hard drive, flash-based drive or camera media card making the files permanently unrecoverable.... Read more
250 iPhone 6 Tips eBook Released for $1.99
Bournemouth, UK based iOS Guides has released 250 iPhone 6 Tips, a new eBook available in the iBookstore that reveals a wealth of tips and tutorials for iPhone 6 and iPhone 6 Plus. Priced at $1.99,... Read more
TigerText Introduces First Secure Enterprise...
TigerText, a provider of secure, real-time messaging for the enterprise, has announced the launch of TigerText for the Apple Watch. TigerText for the Apple Watch enables users to securely send and... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
DevOps Software Engineer - *Apple* Pay, iOS...
**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* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.