TweetFollow Us on Twitter

Using C++ Objects In A Handle-Based World

Using C++ Objects In A Handle-Based World

ANDY SHEBANOW

Although C++ is a powerful and flexible language, its image of the world inside your computer was shaped by operating systems that were a bit more "traditional" than the Macintosh's. As a result, C++ routines that work fine for MPW tools can cause severe problems when used in a Macintosh application. But there are ways around these problems. This article describes a technique that allows you to use normal C++ objects in your Macintosh applications without undue discomfort.

Using C++ objects in the handle-based world of the Macintosh Memory Manager can get pretty tricky at times. The Apple extension to C++ that solves the memory allocation problems you're bound to run into can create other headaches for you if you need to use one or more of several important C++ features in your program. In this article, you'll learn about the memory allocation problems you can expect to encounter when you create objects in C++. You'll also learn how to get around these problems while still retaining the use of important C++ features, by creating a special class PtrObject. You'll see a sample program that uses PtrObject, and you'll learn how to implement the class.

PROBLEMS WITH MEMORY ALLOCATION FOR OBJECTS IN C++

In C++, objects are created dynamically with the new operator, and disposed of with the delete operator when you've finished with them, like this:

TMyObject* aMyObjectRef;
aMyObjectRef = new TMyObject;       // Create a TMyObject object.
aMyObject->AReallyCoolRoutine(); // Do something useful...
delete aMyObject;                   // Delete the object.

When you use these operators, C++ transforms them into calls to operatornew and operator delete. The default versions of operatornewand operatordeleteprovided in the C++ library use the C Standard Library routines malloc and free, respectively, to allocate and deallocate the memory needed to store the object. (Actually, the calloc routine is called to allocate the memory, but callocjust turns around and calls malloc to do the real work.)

These routines work fine for MPW tools, but they can cause the following severe problems when used in a Macintosh application:

  • Heap fragmentation. Nonrelocatable memory for your objects can be allocated in the middle of your heap, preventing the Mac's Memory Manager from compacting memory properly.
  • Heap space permanently wasted. Because calloc and free manage their own list of free memory blocks and never return unused space to the Mac's Memory Manager, if you create a lot of C++ objects your program can run out of memory and crash even though you have plenty of free memory available. (See the sidebar "Everything You Didn't Want to Know About malloc and free" for more information on malloc internals.)
Fortunately, you can override the default versions of operatornewand operatordelete in your own classes to get explicit control over memory allocation. To help you do this, Apple extended C++ to include a predefined base class called HandleObject. If classes you define inherit from HandleObject, the Mac's NewHandle and DisposHandletraps are called instead of the default operator new and operator delete routines.

While this solves the memory problems just mentioned, it also precludes the use of several important C++ features. Here is a partial list of the restrictions that apply when classes you define inherit fromHandleObject:

  • It is an error to declare global variables, local variables, arrays, members, or param- eters of handle-based classes (rather than pointers to them).
  • Multiple inheritance cannot be used with handle-based classes.
  • Handle-based objects can be created only by the new operator. The only use of a dereferenced handle-based class pointer (for example, *x) is to refer to a field in the class (for example, *x.y or x->y).
  • It is not possible to allocate an array of handle-based objects--for example, new->MyObjects[10].
As you can see, there are quite a few useful things you can't do in C++ if you use HandleObject. Most programs should be able to live with these restrictions, but if your program needs to use multiple inheritance or arrays of objects, a different solution is called for.

EVERYTHING YOU DIDN'T WANT TO KNOW ABOUT MALLOC AND FREE

Why do the malloc and free routines wreak so much havoc in a Macintosh application? The main reason is that these routines were originally written for UNIX systems, which have no built-in memory allocation facilities. So these library routines ended up doing everything themselves, including free list management.

This isn't all bad, since these routines are simpler and faster than their Macintosh Memory Manager equiva- lents, but they can cause the severe problems listed earlier in this article for a Macintosh application. The worst part is that these problems can occur even if your application doesn't callmalloc directly. In many situ- ations, C++ callsmalloc for you, as do many of the other routines in the standard library.

Here's how it all works (in MPW, at least):

When you request some memory frommalloc, it rounds the size up to the nearest power of 2 (8-byte mini- mum, ID checked at the door). If you ask for more than 2048 bytes, malloc just calls NewPtr to allocate the memory, and DisposPtr to get rid of it. Otherwise,malloc checks its internal free list looking for blocks of the specified size. If it doesn't find any blocks of that size, it allocates a chunk of memory with NewPtr big enough to hold 2K worth of blocks (plus 2 bytes overhead per block), and adds the new blocks to the free list for that size. It then returns you the first block off of the free list.

When you dispose of memory with the free routine, it looks at the block header to determine which free list to put the block in, and inserts it into the list (sorted by block address to allow for more intelligent freestore management in the future). Here's what a small free list looks like:

[IMAGE C++_Objects_v007_html1.GIF]

MPW (and other Mac development systems) provides versions of these routines to make life easier for people who are porting code from UNIX systems (or MS-DOS, OS/2, etc.). However, since the malloc routine calls NewPtr rather indiscrimately, it can cause blocks to be allocated in very inconvenient places inside your heap, and once these blocks have been allocated, they are never disposed of.

In just one possible scenario, the user opens a large document with your program SuperOOPWrite and cre- ates 1000 standard C++ objects (each allocated by malloc) to represent the elements of the document, each about 100 bytes long. malloc asks NewPtr to create 63 blocks of memory (about 2K each), and you have about 100K less free memory than you used to. Now the user closes the document, and you dutifully dispose of all of your objects. Guess what? You still have 100K less memory available to you as far as the Mac's Memory Manager is concerned, your heap is chock full of 2K nonrelocatable blocks, and you don't have any way to preflight memory for the next time the user wants to open a document.

By the way, if this algorithm sounds familiar to you, it's because the MPW code is based on a public domain version of malloc written by Chris Kingsley.

THE SOLUTION: CREATING A SPECIAL CLASS PTROBJECT

The solution to memory allocation problems when you can't use HandleObject is to create a special class PtrObject analogous to the HandleObject class. This class overrides both operatornewand operatordelete, so that real Memory Manager pointers are used instead of the pointers returned by the default operatornew. PtrObjectalso supports the allocation of objects into a separate heap, which further reduces memory fragmentation.

The method functions of the class PtrObject are as follows:

AllocHeapThis function creates a separate heap. All descendants of class PtrObject cre- ated after calling this function will use this heap. If you do not call this function in your program, the default (application) heap will be used.
DisposeHeap This function disposes of the heap allocated by a previous call to AllocHeap. You should call this function before quitting your application. Any PtrObjects created inside the heap will be invalid, so make sure that you aren't using any of those objects anymore (neither operatordelete nor the destructor for these objects will be called).
FreeMemory This function returns the amount of free space in the PtrObject heap, as returned by the trap FreeMem. If no separate heap exists, this function will return the amount of free memory in the default (application) heap.
MaxMemory This function returns the size of the largest free block in the PtrObject heap, as returned by the trap MaxMem. If no separate heap exists, this function will return the amount of free memory in the default (application) heap.
operator newThis function is called by the C++ compiler to allocate memory for PtrObjects. You never need to call it directly.
operator deleteThis function is called by the C++ compiler to deallocate memory used by PtrObjects. You never need to call it directly.

Here is the class declaration for PtrObject, which would normally be found in the header file PtrObject.h.

class PtrObject {
public:
    static OSErr    AllocHeap(size_t heapSize);
    // Create a heap heapSize bytes long to allocate
    // objects in.
    
    static void DisposeHeap();
    // Free up the heap allocated by a previous call
    // to AllocHeap.

    static long FreeMemory();
    // Return the total amount of free space in the heap.

    static Size MaxMemory();
    // Return the size of the largest free block in the heap.
    
    void*       operator new(size_t size);
    void        operator delete(void* p);
    // These are our special allocation and
    // deallocation operators.

private:
    static THz  fZone;  
    // Our private zone pointer.
};

Notice that the AllocHeap, DisposeHeap, FreeMemory, and MaxMemory calls are all static member functions, and that the fZone variable is a static data member . In C++, static members are shared across all instances of a class. You should use static members in place of global variables and functions whenever possible, since they have limited scope (which means fewer name conflicts) and they are logically tied to the class in which they are declared (which means more readable source code). To call a static member function, the syntax is

ClassName::StaticFunctionName(/* parameters, if any */);

A SAMPLE PROGRAM USING PTROBJECT

Now that you've seen the interface to the PtrObject class, here is a small sample application that uses it. This program isn't very useful-- all it does is define a subclass of PtrObject, create an instance of that object, and call one of its methods.

The first thing we have to do is the standard setup for a Macintosh application, which in this case means including all of the needed header files for the Macintosh Toolbox and the C Standard Library:

// TestPtrObject.cp
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <SegLoad.h>
#include <Events.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Memory.h>
#include <OSUtils.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>

Next we include the header file for the PtrObject class (just shown), and define a new class TLout that is derived from it:

#include "PtrObject.h"

// A small class that contains some data and a constructor,
// but spends all of its time on street corners cadging
// cigarettes instead of doing useful work.

class TLout : public PtrObject {
public:
    TLout() { DoCadge(); }; // Our constructor.
    virtual void    DoCadge();  // A rude member function.
private:
    char        fArray[256];
};

void TLout::DoCadge()
{
    strcpy(fArray,"Hey buddy, spare a cig?");
}

That's all it takes to define a class with the correct memory management behavior. Here is the main program, which uses our newly defined TLout class:

void InitToolbox();     // Forward declaration.

main()
{
    // We need this much space to store the objects
    // we're going to initialize - in this case, 16KBytes.
    const size_t kDefaultHeapSize = 0x4000;
    
    InitToolbox();  // Initialize Mac Toolbox (ho hum).
    
    // Create a heap for PtrObjects to live in.
    OSErr heapErr = PtrObject::AllocHeap(kDefaultHeapSize);
    
    // If we got an error, quit - this isn't a real
    // application, so we don't need error handling, right?
    if (heapErr != noErr)
       ExitToShell();   

    // Create an object - will go in separate heap automatically.
    TLout* aLout = new TLout;   // Do that voodoo that TLouts do...
    if (aLout != nil)
     {
        aLout->DoCadge();
        delete aLout;       
              // Delete our object now that we have finished with it.
     }

    // Dispose of the heap.
    PtrObject::DisposeHeap();
    ExitToShell();
}

One important thing needs to be pointed out here: you need to call PtrObject::AllocHeap as early in your program as possible, or the newly created heap may fragment your application heap. Finally, just for completeness, here's the implementation of the InitToolbox routine, which makes sure that all of the necessary pieces of the Mac Toolbox are initialized:

voidInitToolbox()
{
    //StandardMacintoshinitialization.
    InitGraf((Ptr)&qd.thePort);
    InitFonts(); InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    MaxApplZone();
}

THE SAMPLE PROGRAM'S MAKEFILE

# TestPtrObject.make
# by Andrew Shebanow (with some help from the CreateMake script)

OBJECTS = ð
    PtrObject.cp.o ð
    TestPtrObject.cp.o

SymOptions = -sym on
CPlusOptions = {SymOptions}

{OBJECTS} ƒƒ PtrObject.h

TestPtrObject ƒƒ {OBJECTS}
Link -w {SymOptions} -mf {OBJECTS} ð
    "{CLibraries}"CSANELib.o ð
    "{CLibraries}"Math.o ð
    "{CLibraries}"CPlusLib.o ð
    "{CLibraries}"StdCLib.o ð
    "{CLibraries}"CInterface.o ð
    "{CLibraries}"CRuntime.o ð
    "{Libraries}"Interface.o ð
    -o TestPtrObject

PtrObject.cp.o ƒ PtrObject.cp PtrObject.h
TestPtrObject.cp.o ƒ TestPtrObject.cp PtrObject.h

IMPLEMENTING PTROBJECT

Now that we've seen how to use class PtrObject, we need to implement it. We must first include all the necessary header files and allocate our static member data:

// PtrObject.cp
#include <Memory.h>
#include <Errors.h>
#include <stdio.h>
#include <stddef.h>
#include "PtrObject.h"

// Static data members actually need to be declared outside of the
// class definition in order to have space allocated.
THz PtrObject::fZone = nil;

Next we have the AllocHeapfunction.

OSErr PtrObject::AllocHeap(size_t heapSize)
{
    // By default, the heap gets kNumDfltMasters master pointers.
    // A small number, but it shouldn't matter, since we will only
    // be allocating Ptrs in this heap and Ptrs don't use master
    // pointers. 
    const short kNumDfltMasters = 16;

    // This magic number from Inside Mac, vol. II, chapter 1, is
    // the amount of space required for the zone header and trailer,
    // and the master pointer block. We add this to the requested
    // heap size to compensate.
    const size_t kZoneOverhead =
        64 + 8 + (sizeof(long) * kNumDfltMasters);

    heapSize += kZoneOverhead;      // Factor in overhead.

    // Allocate space for the zone.
    Ptr zonePtr = NewPtr(heapSize); 
    if (!zonePtr)           // if alloc fails, return error
        return MemError();  // Get a pointer to the end of the heap.

    Ptr limitPtr = (Ptr) (((ptrdiff_t) zonePtr) + heapSize);
    
    // Initialize the zone.
    InitZone(nil, kNumDfltMasters, limitPtr, zonePtr);

    // Save the zone pointer in our static class variable.
    fZone = (THz) zonePtr;
    return noErr;
}

The DisposeHeap member function is much simpler. It just checks to see if we allocated a zone in the past, and if so, it disposes of the heap's memory. This will destroy any objects that were allocated inside the heap, which could be dangerous, so be careful when you call this routine.

void PtrObject::DisposeHeap()
{
    // If zone actually exists, dispose of it.
    if (fZone)
     {
        DisposPtr((Ptr) fZone);
        fZone = nil;
     }
}

Next we have the FreeMemory and MaxMemoryfunctions. We'll show them together, since they are almost identical. The only thing of note here is the way we switch in our special heap if it exists.

long PtrObject::FreeMemory()
{
    THz savedZone;
                    // Before we can return the amount of free 
                    // memory, we need to switch to the correct zone.
    if (fZone)
     {
        savedZone = GetZone();      // Save current zone.
        SetZone(fZone);         // Make our zone current.
     }

    long free = FreeMem();      // Get total free space.

    if (fZone)
      SetZone(savedZone);       // Restore previous zone.
    return free;
}

Size PtrObject::MaxMemory()
{
    THz savedZone;
                    // Before we can return the maximum block size,
                    // we need to switch to the correct zone.
    if (fZone)
     {
        savedZone = GetZone();      // Save current zone.
        SetZone(fZone);         // Make our zone current.
     }

    Size tSize;             // We know the heap can't grow,
                            // but we have to have a temp
                        // variable to satisfy the Toolbox.
    Size max = MaxMem(&tSize);      // Get size of biggest block.
    if (fZone)
      SetZone(savedZone);       // Restore previous zone.
    return max;
}

Now we get to the heart of the class, the operator new function. Like the FreeMemory call, operator newswitches to our private heap before it actually allocates memory, and restores the previous heap when it is done. The actual memory allocation is done by a call to everyone's favorite Macintosh trap, NewPtr.

void* PtrObject::operator new(size_t size)
{
    THz savedZone;

    // before we can allocate memory, we need to switch to the
    // correct zone
    if (fZone)
     {
        savedZone = GetZone();  // Save current zone.
        SetZone(fZone);         // Make our zone current.
     }
    Ptr p = NewPtr(size);       // Allocate memory for object.
    if (fZone)
      SetZone(savedZone);       // Restore previous zone.
    return p;
}

Last, we have the operator delete function. All it does is dispose of the memory occupied by the object. We don't need to swap in the private heap here, since the Memory Manager keeps track of the heap that the pointer belongs to for us.

void PtrObject::operator delete(void* p)
{
    DisposPtr((Ptr) p);         // This works regardless of the zone
                                // the pointer was allocated in.
}

That's all there is to the PtrObject class. If you wish to explore the stranger side of C++ (multiple inheritance and so on), you should use it, since it allows your creations to live in the complicated world of the Macintosh Memory Manager.

ANDY SHEBANOW , a DTS engineer, wrote this article for the best of reasons: "The beer people had their say in the last issue, and it's about time the Mountain Dew people spoke up." His highly developed personal skills have earned him the affectionate nickname "The Shebanator." After working for a medical imaging company, he joined Apple twenty-odd months ago. It's been so long since he was outside that he's forgotten what his hobbies are; he vaguely remembers some- thing about driving cars at excessive and/or illegal speeds.*Consult the MPW C++ Reference , available from APDA as part of the MPW C++ package, for a full list of restrictions on C++ features in effect when classes you define inherit from HandleObject.*

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

OS X Server 4.1.3 - For OS X 10.10 Yosem...
Designed for OS X and iOS devices, OS X Server makes it easy to share files, schedule meetings, synchronize contacts, develop software, host your own website, publish wikis, configure Mac, iPhone,... Read more
pwSafe 4.1 - Secure password management...
pwSafe provides simple and secure password management across devices and computers. pwSafe uses iCloud to keep your password databases backed-up and synced between Macs and iOS devices. It is... Read more
Kodi 15.0.rc1 - Powerful media center to...
Kodi (was XBMC) is an award-winning free and open-source (GPL) software media player and entertainment hub that can be installed on Linux, OS X, Windows, iOS, and Android, featuring a 10-foot user... Read more
Coda 2.5.11 - One-window Web development...
Coda is a powerful Web editor that puts everything in one place. An editor. Terminal. CSS. Files. With Coda 2, we went beyond expectations. With loads of new, much-requested features, a few surprises... Read more
Bookends 12.5.7 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Access the power of Bookends directly from Mellel, Nisus Writer Pro, or MS Word (... Read more
Maya 2016 - 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
RapidWeaver 6.2.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
MacFamilyTree 7.5.2 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
Paragraphs 1.0.1 - Writing tool just for...
Paragraphs is an app just for writers. It was built for one thing and one thing only: writing. It gives you everything you need to create brilliant prose and does away with the rest. Everything in... Read more
BlueStacks App Player 0.9.21 - Run Andro...
BlueStacks App Player lets you run your Android apps fast and fullscreen on your Mac. Version 0.9.21: Note: Now requires OS X 10.8 or later running on a 64-bit Intel processor. Initial stable... Read more

Rage of Bahamut is Giving Almost All of...
The App Store isn't what it used to be back in 2012, so it's not unexpected to see some games changing their structures with the times. Now we can add Rage of Bahamut to that list with the recent announcement that the game is severely cutting back... | Read more »
Adventures of Pip (Games)
Adventures of Pip 1.0 Device: iOS iPhone Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** ONE WEEK ONLY — 66% OFF! *** “Adventures of Pip is a delightful little platformer full of charm, challenge and impeccable... | Read more »
Divide By Sheep - Tips, Tricks, and Stre...
Who would have thought splitting up sheep could be so involved? Anyone who’s played Divide by Sheep, that’s who! While we’re not about to give you complete solutions to everything (because that’s just cheating), we will happily give you some... | Read more »
NaturalMotion and Zynga Have Started Tea...
An official sequel to 2012's CSR Racing is officially on the way, with Zynga and NaturalMotion releasing a short teaser trailer to get everyone excited. Well, as excited as one can get from a trailer with no gameplay footage, anyway. [Read more] | Read more »
Grab a Friend and Pick up Overkill 3, Be...
Overkill 3 is a pretty enjoyable third-person shooter that was sort of begging for some online multiplayer. Fortunately the begging can stop, because its newest update has added an online co-op mode. [Read more] | Read more »
Scanner Pro's Newest Update Adds Au...
Scanner Pro is one of the most popular document scanning apps on iOS, thanks in no small part to its near-constant updates, I'm sure. Now we're up to update number six, and it adds some pretty handy new features. [Read more] | Read more »
Heroki (Games)
Heroki 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: CLEAR THE SKIES FOR A NEW HERO!The peaceful sky village of Levantia is in danger! The dastardly Dr. N. Forchin and his accomplice,... | Read more »
Wars of the Roses (Games)
Wars of the Roses 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
TapMon Battle (Games)
TapMon Battle 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: It's time to battle!Tap! Tap! Tap! Try tap a egg to hatch a Tapmon!Do a battle with another tapmons using your hatched tapmons! *... | Read more »
Alchemic Dungeons (Games)
Alchemic Dungeons 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: ### Release Event! ### 2.99$->0.99$ for limited time! ### Roguelike Role Playing Game! ### Alchemic Dungeons is roguelike... | Read more »

Price Scanner via MacPrices.net

Seagate Backup Plus Drives Feature 200GB of C...
Seagate Technology plc has announced that its Backup Plus family of external storage offerings will now include 200GB of OneDrive cloud storage, a major added value, and the addition of Lyve’s photo... Read more
Canon PIXMA MG3620 Wireless Inkjet All-in-One...
Canon U.S.A., Inc. has announced the PIXMA MG3620 Wireless (1) Inkjet All-in-One (AIO) printer for high-quality photo and document printing. Built with convenience in mind for the everyday home user... Read more
July 4th Holiday Weekend 13-inch MacBook Pro...
Save up to $150 on the purchase of a new 2015 13″ Retina MacBook Pro at the following resellers this weekend. Shipping is free with each model: 2.7GHz/128GB MSRP $1299 2.7GHz/... Read more
27-inch 3.5GHz 5K iMac on sale for $2149, sav...
Best Buy has the 27″ 3.5GHz 5K iMac on sale for $2149.99. Choose free shipping or free local store pickup (if available). Sale price for online orders only, in-store prices may vary. Their price is $... Read more
Apple now offering refurbished 2015 11-inch...
The Apple Store is now offering Apple Certified Refurbished 2015 11″ MacBook Airs as well as 13″ MacBook Airs (the latest models), available for up to $180 off the cost of new models. An Apple one-... Read more
15-inch 2.5GHz Retina MacBook Pro on sale for...
Amazon.com has the 15″ 2.5GHz Retina MacBook Pro on sale for $2274 including free shipping. Their price is $225 off MSRP, and it’s the lowest price available for this model. Read more
Finally Safe To Upgrade To Yosemite’?
The reason I’ve held back from upgrading my MacBook Air from OS X 10.9 Mavericks to 10.10 Yosemite for nearly a year isn’t just procrastination. Among other bugs reported, there have been persistent... Read more
Logo Pop Free Vector Logo Design App For OS X...
128bit Technologies has released of Logo Pop Free 1.2 for Mac OS X, a vector based, full-fledged, logo design app available exclusively on the Mac App Store for the agreeable price of absolutely free... Read more
21-inch 1.4GHz iMac on sale for $999, save $1...
B&H Photo has new 21″ 1.4GHz iMac on sale for $999 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Best Buy has the 21″ 1.4GHz iMac on sale for $999.99 on their... Read more
16GB iPad mini 3 on sale for $339, save $60
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $339 including free shipping plus NY tax only. Their price is $60 off MSRP. Read more

Jobs Board

Mobile Payments Counsel, *Apple* Pay (digit...
**Job Summary** Apple is looking for an atto ey to join Apple 's Legal Department to support Apple Pay. **Key Qualifications** 4+ years of relevant experience Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** The ASC is an Apple employee who serves as the Apple business manager and influencer in a hyper-business critical Reseller's store which delivers Read more
Partner Marketing Manager, Merchant- *Apple*...
**Job Summary** The Apple Pay partner marketing team is looking for a marketing manager to develop and drive US marketing programs with our merchant partners. The right 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
Program Manger, WW *Apple* Direct Fulfillme...
**Job Summary** We are seeking a business analyst to work within our Worldwide Apple Direct Fulfillment Operations team. This role will work closely with related program Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.