TweetFollow Us on Twitter

The Road to Code: There's a Hole in your Bucket

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

The Road to Code: There's a Hole in your Bucket

Objective-C Memory Management

by Dave Dribin

Introduction

Welcome back to The Road to Code. In previous articles, we've talked about dynamic memory management and how to use malloc and free in C. We've also covered using alloc and release in Objective-C. Unfortunately, I left out a lot of the details of Objective-C memory management, mentioning only that alloc and release worked the same as malloc and free. This was a white lie, and the truth is that they are a bit more complicated. While the complications are a bit of a hurdle to overcome, they paradoxically make it easier on the programmer, in the long run.

Object Ownership

Let's assume, for a bit more, that the alloc method allocates memory for an object and the release method immediately deallocates it. For the simple programs we've written so far, it's easy to remember when to call release. Take this simple example where we use our Rectangle class in Listing 1:

Listing 1: Using the Rectangle class

#import <Foundation/Foundation.h>
#import "Rectangle.h"
int main (int argc, const char * argv[])
{
   NSAutoreleasePool * pool =
      [[NSAutoreleasePool alloc] init];
   Rectangle * rectangle;
   
   rectangle = [[Rectangle alloc] initWithLeftX   : 5
                                 bottomY   : 5
                                  rightX   : 15
                                   topY   : 10];
   printf("Area is %.2f\n", [rectangle area]);
   printf("Perimeter is: %.2f\n", [rectangle perimeter]);
   
   [rectangle release];
   
   [pool release];
   return 0;
}

We've allocated a Rectangle instance at the beginning of main so we just need to remember to call release to deallocate it at the end of main before it returns. However, as programs get larger and start running for longer periods of time, the task of how and when to release memory becomes daunting. You may have two objects that both are using the same Rectangle instance, for example, by showing the rectangle in two different windows. This would give you an object graph that looks like Figure 1:


Figure 1: Simple object graph

Both object_1 and object_2 have references to the same instance of a Rectangle class, rectangle. Which object, object_1 or object_2, has the responsibility to release rectangle when they get released and deallocated? If neither of them call release, then you end up in a situation like Figure 2.


Figure 2: Leaking an object

rectangle now exists with no other object pointing to it, so it is lost to the system and taking up memory. This is called a memory leak, and memory leaks are serious bugs. If you have memory leaks in a long-running program, such as a GUI application, then the program will be using more and more memory as it runs. Pretty soon, it could be using most of the memory in the system. This leads to a bad user experience, as memory is being used for dead and no longer used objects, instead of useful stuff.

Okay, so clearly not releasing used objects is a bad thing. But on the other end of the spectrum of memory problems, you can also over-release an object. Say that both object_1 and object_2 decide they should be responsible for releasing rectangle. Now, if object_2 is released and deallocated, it releases and deallocates rectangle along with it. You end up with a situation like Figure 3:


Figure 3: Dangling pointer

Oops! Now object_1 is pointing to memory that was previously used by rectangle, but has now been deallocated and returned to the system. This situation is called a dangling pointer. Dangling pointer bugs manifest themselves in strange ways and can be hard to track down. Since memory returned to the system may not be recycled and reallocated for other purposes right away, object_1 might be able to use rectangle after its death. It will continue to work...for a bit. But then, at some point, your program may start acting really strange or outright crash. Because the symptoms of the bug are delayed - the bug actually occurred where rectangle was prematurely released - these kinds of bugs are hard to squash.

In order to avoid both memory leaks and dangling pointers, we need to make sure that objects are only deallocated after all objects pointing to them are finished. One way to do this is with the concept of ownership. We can setup a system where every object is owned by one and only one other object, and only the owner is responsible for releasing the object. Also, object ownership can be transferred from one object to another. For example, take Figure 1 again. If object_1 owns rectangle, then when object_2 is deallocated it does not take rectangle with it. If, on the other hand, object_2 is the owner, it may pass ownership to object_1. Thus, when object_1 is deallocated, it will take rectangle with it.

As you can begin to see, even from this simple example, the concept of ownership can be hard to manage. How do you notify object_1 that it now owns rectangle? What if a third object, object_3, is created before object_1 is deallocated and it also uses rectangle? object_1 needs to somehow know about this and transfer ownership, instead of releasing rectangle upon deallocation. There are ways to manage the single ownership problem, but they can be difficult to get right. Thankfully, Objective-C gives us a better way.

Reference Counting

Instead of having single ownership, with one and only one owner, Objective-C embraces shared ownership. Thus object_1 and object_2 both own rectangle. rectangle does not need to know who its owners are; it just needs to keep track of the number of owners. When the number of owners drops to zero, then it's deallocated. The number of owners is called a reference count since it counts how many other objects reference (point to) it. I've modified the original object graph in Figure 4 to also show the reference count of rectangle. Thus when object_2 releases rectangle, it decrements the reference count from two to one. Since the reference count is still greater than zero, it is not deallocated and is available for object_1. When object_1 also releases it the reference count will be zero, and rectangle will finally be deallocated.


Figure 4: Reference count

This also fixes our situation where object_3, which also uses rectangle, is created before object_1 releases rectangle. The reference count for rectangle goes back up to two. Thus if object_1 releases rectangle, the reference count will be one and it will live until object_3 also releases it.

Okay, so that's the theory. How do you actually use reference counting in Objective-C? You've already been partially using it. All objects that inherit from NSObject (which are all objects) already contain a reference count. The release method does not deallocate the memory straight away, like the free function does. Instead, it subtracts one from the reference count, and only if the new reference count is zero will it deallocate the memory.

So release decrements (reduces) the reference count, but how do you increase the reference count? When an object is created with the alloc it is given a reference count of one. Thus, if we look at our program in Listing 1, you'll see why releasing rectangle deallocates it. If you need to increase the reference count there is a method called retain that does just this. Because Objective-C uses the retain method, the reference count in Objective-C is also called the retain count. Same thing, different name. In fact, you can even get the retain count of an object with the retainCount method. Listing 2 demonstrates the retain count.

Listing 2: Retain counts

#import <Foundation/Foundation.h>
#import "Rectangle.h"
int main (int argc, const char * argv[])
{
   NSAutoreleasePool * pool =
      [[NSAutoreleasePool alloc] init];
   
   Rectangle * rectangle;
   
   rectangle = [[Rectangle alloc] initWithLeftX   : 5
                               bottomY   : 5
                                rightX   : 15
                                 topY   : 10];
   
   printf("Retain count: %d\n", [rectangle retainCount]);
   
   [rectangle retain];
   printf("Retain count: %d\n", [rectangle retainCount]);
   
   [rectangle release];
   printf("Retain count: %d\n", [rectangle retainCount]);
   [rectangle release];
   [pool release];
   return 0;
}

When run, this program will output:

Retain count: 1
Retain count: 2
Retain count: 1

As an aside, while using retainCount can be interesting to see how reference counting works in Objective-C, you should only use it for debugging purposes. There are cases when the retain count is not telling the whole story, especially when autorelease pools (discussed below) come into play.

While Objective-C has built in support for shared ownership via reference counting, it is still an explicit step that all Objective-C programmers need to use properly. If you take away only one thing from this article, let it be this rule: every alloc and retain must be balanced by a corresponding release. Thus, in the example above, because we allocate the object and retain it once more, we need to release it twice.

Since it is a manual step, you can still get memory leaks if you forget to release an object after retaining it, and you can get dangling pointers if you release an object without first retaining it. Because the programmer must explicitly manage the reference count with retain and release, this is called manual reference counting. Other languages, such as Python, have automatic reference counting, where the language takes care of incrementing and decrementing the reference count for you. Alas, we Objective-C programmers have to do it manually, but at least we have it better than straight C programmers.

Retaining and Releasing in Accessors

Listing 2 is not a realistic usage of retaining and releasing objects, though, as you rarely retain an object for no reason. The reason you would retain an object is to take shared ownership in it. Let's create a new class called RectanglePrinter that holds onto a Rectangle instance and prints information about it. Listing 3 shows the interface for this class.

Listing 3: RectanglePrinter.h

#import <Foundation/Foundation.h>
#import "Rectangle.h"
@interface RectanglePrinter : NSObject
{
   Rectangle * _rectangle;
}
- (Rectangle *) rectangle;
- (void) setRectangle: (Rectangle *) rectangle;
- (void) printArea;
@end

To use this new class, let's use the test program in Listing 4.

Listing 4: RectanglePrinter test application

#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "RectanglePrinter.h"
int main(int argc, const char * argv[])
{
   NSAutoreleasePool * pool =
      [[NSAutoreleasePool alloc] init];
   
   Rectangle * rectangle;
   
   rectangle = [[Rectangle alloc] initWithLeftX   : 5
                               bottomY   : 5
                                rightX   : 15
                                 topY   : 10];
   
   RectanglePrinter * printer =
      [[RectanglePrinter alloc] init];
   
   [printer setRectangle: rectangle];
   [rectangle release];
   rectangle = nil;
   
   [printer printArea];
   [printer release];
   
   [pool release];
   return 0;
}

Let me point out a couple of things here. First, after calling setRectangle:, we release our instance, since we are no longer in need of it. This does not deallocate rectangle, though, since setRectangle: should take additional ownership and increase the retain count. We also set rectangle to nil after its release. nil is a special value that can be assigned to any object pointer, and it means the pointer points to no object at all. It's good practice to set your object pointers to nil after releasing them. While it won't matter if you've written your program without any bugs, it can help while debugging if you've made a mistake dealing with the retain counts.

Before diving into the implementation, there's a little more terminology to cover. Remember that instance variables are private and should only be used internally to the class. If you want to make an instance variable, like _rectangle, available outside your class, you should use methods to keep encapsulation intact. The pair of methods, rectangle and setRectangle:, expose the _rectangle instance variable publicly and are called accessor methods. The rectangle method is called a getter and setRecangle: is called a setter. The getter and setter pair of accessor methods is an important design pattern that we will be seeing more of in advanced Objective-C topics.

The implementation of RectanglePrinter shows how to use retain to take ownership for accessor methods, and is shown in Listing 5.

Listing 5: RectanglePrinter.m, first version

#import "RectanglePrinter.h"
@implementation RectanglePrinter
- (Rectangle *) rectangle
{
   return _rectangle;
}
- (void) setRectangle: (Rectangle *) rectangle
{
   if (rectangle == _rectangle)
      return;
   
   [_rectangle release];
   _rectangle = [rectangle retain];
}
- (void) printArea
{
   printf("Rectangle area: %.2f\n", [_rectangle area]);
}
@end

The rectangle method is simple: it just returns the _rectangle instance variable. This is how most getter methods should be implemented. The setRectangle: method is a bit more complicated, though. Notice that retain also returns the object, so you can perform the retain and assignment in a single step. You might be tempted to implement it as follows, by first releasing the current rectangle, and the retaining the new one:

- (void) setRectangle: (Rectangle *) rectangle
{
   [_rectangle release];
   _rectangle = [rectangle retain];
}

However, don't do it! This causes issues if the new rectangle is the same instance as the old one and the current retain count is already one. If this happens to be the case, releasing the object would cause it be deallocated before the retain happened, and you'd end up retaining a dead object. While this does not happen very often, it can happen, so it's wise to follow the pattern in Listing 5 and check for identical instances in all your setters. There are other correct ways of writing accessor methods, and indeed the "correct" way is still a topic of debate, but the pattern covered here covers the vast majority of situations.

Destructors

There's still one more bug lurking in this code. If calling release on a RectanglePrinter causes it to be deallocated, the Rectangle instance pointed to by the _rectangle instance variable is leaked. This is because we did a retain in setRectangle: but never paired this up with a release. What we really need is a way to be notified that our object is about to be deallocated so we can clean up any objects we're using. Thankfully, Objective-C calls a method named dealloc just before deallocating your object to give you a chance to do just that. Here's how we would implement it:

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

Because dealloc is called when the object is just about to be reclaimed for system usage, it is called a destructor. This terminology also pairs up with the init method being called a constructor, as we talked about in the previous article.

You may be wondering about the case where _rectangle is nil. Calling methods on objects set to nil does nothing at all. Thus, it's safe to call release on nil. This may seem odd if you're coming from a C++ or Java background where calling methods on an object set to null (their equivalent of nil) will cause your program to crash. This is one of the oddball Objective-C moments. Some people love it and some people hate it. Whatever your take, you may as well just live with it and embrace it, because it's not going to change.

You may also be wondering what _rectangle is set to if you never call setRectangle:. All instance variables are set to nil automatically by the default constructor (the init method of NSObject), so our code will work just fine. However, some people like to explicitly set objects to nil in a custom constructor. Listing 6 shows the complete implementation of RectanglePrinter, complete with constructor and destructor, accessor methods, and printArea.

Listing 6: RectanglePrinter.m, complete

#import "RectanglePrinter.h"
@implementation RectanglePrinter
- (id) init
{
   self = [super init];
   if (self == nil)
      return nil;
   
   _rectangle = nil;
   
   return self;
}
- (void) dealloc
{
   [_rectangle release];
   [super dealloc];
}
- (Rectangle *) rectangle
{
   return _rectangle;
}
- (void) setRectangle: (Rectangle *) rectangle
{
   if (rectangle == _rectangle)
      return;
   
   [_rectangle release];
   _rectangle = [rectangle retain];
}
- (void) printArea
{
   printf("Rectangle area: %.2f\n", [_rectangle area]);
}
@end

Retain Cycles

While reference counting is an effective technique to help deal with memory management, it can break down in one case. If two objects both reference each other, you end up with a situation where the retain count will never reach zero. This is because their retain counts will be stuck at one. Figure 5 shows how this can happen, where parent and child retain each other (see below):


Figure 5: Retain cycles cause memory leaks

When object_1 is deallocated, it releases its reference to parent. However, since child also references parent, the retain count can never reach zero, and we're stuck leaking an instance of both parent and child.

The trick to this is to have child contain a reference to parent, but not retain it. This is called a weak reference. By having child not retain parent, the reference count for parent is only one, as in Figure 6.


Figure 6: Using weak reference to break retain cycles

The key for this to actually work in practice is to explain, in a comment, that it is a weak reference, so that other developers will understand why a retain and release are not done on this reference. An example is shown in Listing 7.

Listing 7: Weak references

#import <Cocoa/Cocoa.h>
@class Parent;
@interface Child : NSObject
{
   // This is a weak reference.  Do not retain.
   Parent * _parent;
}
- (id) initWithParent: (Parent *) parent;
@end

Delayed Release

Sometimes getter methods do not simply return an instance variable. They may need to create a new object on the fly. Take this method that returns a Rectangle object that is a 4x4 square:

- (Rectangle *) square4x4
{
   Rectangle * square =
      [[Rectangle alloc] initWithLeftX   : 0
                         bottomY   : 0
                          rightX   : 4
                           topY   : 4];
   return square;
}

This looks very similar to any other getter method, except the caller is supposed to release the object when it is done with it. But how is the caller supposed to know this? We could document this in the code comments, but there's a high probably that people will miss this. Or we could rename the method such that it indicates object creation, such as newSquare4x4. But this limits our implementation choices in the future. What if we decided to use an instance variable to keep returning the same object for increased performance? We'd have to change our name back to square4x4 so as not to confuse the caller. The solution to this is to use the autorelease method supplied by NSObject. Thus the correct implementation of square4x4 is:

- (Rectangle *) square4x4
{
   Rectangle * square =
      [[Rectangle alloc] initWithLeftX   : 0
                         bottomY   : 0
                          rightX   : 4
                           topY   : 4];
   return [square autorelease];
}

The autorelease method is similar to release in that it will decrease the reference count, but at some point in the future instead of immediately. Thus, if the caller does not keep a reference to the return value, the object will be properly released. However, if the caller does retain the return value, then the retain count will still only be one. It will temporarily be two, but the delayed release causes the retain count to go back to one.

How does this autorelease thing actually work? The secret is autorelease pools, implemented by the NSAutoreleasePool class. Yup, those are the objects we see in our main class. When the autorelease method is called, the object gets added to the most current autorelease pool. When the pool is released, it also releases all objects in the pool. Thus, in our simple programs, the delayed release occurs just before the main application exits.

Because autorelease may by used internally by parts of the standard Foundation library, including NSObject, every application needs at least one autorelease pool active at all times. That's why the first thing our Objective-C programs do is set up an autorelease pool. We want to ensure an autorelease pool is in place before we start using any other objects. It's also why the last thing our program does is release the autorelease pool.

In GUI applications, you don't need to setup any autorelease pools. The standard Cocoa libraries take care of all this for you. For our command line applications, though, we need to take care of the autorelease pools, ourselves.

Autorelease and Class Methods

The methods we have been using so far only work on an instance of that class, thus they are called instance methods. There is another kind of method that does not require an instance of a class called class methods. These are declared using a plus ('+') instead of a minus sign ('-') as the first character:

+ (void) myClassMethod;

The definition also uses the plus sign, but is otherwise identical to an instance method:

+ (void) myClassMethod
{
   printf("In myClassMethod\n");
}

Since you don't use an object instance to call these methods on, you use the class name when calling class methods. For example, if the above class method were part of the Rectangle class, it would be called like this:

   [Rectangle myClassMethod];

Class methods, because they do not require an instance, are very similar to a function call. The benefit is that the are tied to a particular class. Whether you create a function or a class method really depends on the situation. One particular case where class methods are useful is for creating autoreleased instances in a single step.

Because autoreleased objects make memory management easier when you use short-lived objects, they tend to get used a lot. However, creating them can be a bit a pain. For example, to create an autoreleased instance of our Rectangle class, we need to call three methods:

   rectangle = [[Rectangle alloc] initWithLeftX   : 5
                               bottomY   : 5
                                rightX   : 15
                                 topY   : 10];
   [rectangle autorelease];

To make this common task easier, it is useful to create a class method that does this all in one step:

+ (Rectangle *) rectangleWithLeftX   : (float) leftX
                     bottomY   : (float) bottomY
                     rightX   : (float) rightX
                       topY   : (float) topY;
{
   Rectangle * rectangle =
      [[self alloc] initWithLeftX: leftX
                     bottomY   : bottomY
                      rightX   : rightX
                        topY   : topY];
   return [rectangle autorelease];
}

This could then be used like:

   rectangle = [Rectangle rectangleWithLeftX   : 5
                             bottomY   : 5
                              rightX   : 15
                               topY   : 10];

You will see this "class method for autorelease" pattern in many of the standard Foundation and Cocoa libraries. By convention, the name of the class method starts with the name the class. For example, there's an NSNumber class in Foundation that holds standard C numbers, such as int and float. To create an instance of this, you would use:

   NSNumber * number = [[NSNumber alloc] initWithInt: 42];

To create an autoreleased instance, you would use the numberWithInt: class method:

   NSNumber * number = [NSNumber numberWithInt: 42];

I mention this because the pattern is so heavily used that the documentation often fails to mention the fact that the return object is autoreleased. So just keep this in mind if you see code like this and you are wondering why release is not being called on these objects.

Garbage Collection

While reference counting is a big step up from the malloc and free usage of standard C, it can still be problematic, especially since Objective-C uses manual reference counting. It is easy for a programmer to forget to call release and cause memory leaks. Properly using retain and release is yet another thing programmers have to think about, instead of how to implement new features. Thankfully, there exists another technique for dealing with dynamic memory.

Objective-C 2.0, which was released along with Mac OS X 10.5, Leopard, includes a technique called garbage collection. In short, garbage collection, or GC, works by having the system keep track of all object allocations and assignments. Then, the system will periodically scan all allocated objects, looking for objects that have no references to them. If an object has no references, it is considered garbage and deallocated automatically.

In plain English, this means that you no longer have to use retain, release, or autorelease ever again. Memory management is completely automatic, and the burden of memory leaks, dangling pointers, and retain cycles has been lifted from the backs of Objective-C programmers. This is really huge. Here is our RectanglePrinter test application from Listing 4 written with garbage collection:

Listing 8: Garbage collection example

#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "RectanglePrinter.h"
int main (int argc, const char * argv[])
{
   Rectangle * rectangle;
   
   rectangle = [[Rectangle alloc] initWithLeftX   : 5
                               bottomY   : 5
                                rightX   : 15
                                 topY   : 10];
   
   RectanglePrinter * printer =
      [[RectanglePrinter alloc] init];
   
   [printer setRectangle: rectangle];
   [printer printArea];
   
   return 0;
}

As you can see, we've removed the autorelease pool and all calls to release. Of course, there are still a few finer points you have to worry about, but in general, Apple has delivered on this. Another major difference you will notice is that the dealloc method is no longer called, thus you should not implement it. This is because you no longer need to release your references to other objects. While the lack of dealloc is mainly transparent, there are some cases when you will have to restructure your code a bit. For classes that just release their instance variables, like our RectanglePrinter, it means we can just delete our dealloc method and things will work. We will go over the finer points of GC as we come across them in future articles.

The only major downside at this point is that GC is only supported on Leopard. If you are writing code that needs to execute on prior versions of Mac OS X, you won't be able to use GC, just yet.

Conclusion

Objective-C memory management is a bit different from most other languages out there. Until recently, it used reference counting which is more flexible than malloc and free, but it's not completely automatic. There are a few rules that you must follow in order to properly retain and release objects. This means you must constantly think about and follow the rules in your programs. The advent of Leopard brings us garbage collection and promises to simplify memory management even more. In either case, memory management is a cornerstone of Objective-C programming. With this topic under your belt, we can start exploring areas of the Foundation and Cocoa libraries.


Dave Dribin has been writing professional software for over eleven years. After five years programming embedded C in the telecom industry and a brief stint riding the Internet bubble, he decided to venture out on his own. Since 2001, he has been providing independent consulting services, and in 2006, he founded Bit Maki, Inc. Find out more at http://www.bitmaki.com/ and http://www.dribin.org/dave/.

 
AAPL
$101.79
Apple Inc.
+0.21
MSFT
$46.68
Microsoft Corpora
+0.16
GOOG
$589.27
Google Inc.
+4.50

MacTech Search:
Community Search:

Software Updates via MacUpdate

iMazing 1.0 - Complete iOS device manage...
iMazing (formerly DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and... Read more
Xcode 6.0.1 - Integrated development env...
Apple Xcode is Apple Computer's integrated development environment (IDE) for OS X. The full Xcode package is free to ADC members and includes all the tools you need to create, debug, and optimize... Read more
Apple Safari 7.1 - Apple's Web brow...
Apple Safari in OS X Mavericks brings you all-new ways to find and enjoy the best of the web. It works with iCloud to give you a seamless browsing experience across all your devices. It looks out for... Read more
Delivery Status 6.1.2 - Check delivery s...
Delivery Status displays delivery status of packages for a variety of shipment services. Can't wait for your packages to arrive? Don't waste your time checking the site constantly, just open this all... Read more
Mavericks Cache Cleaner 8.0.9 - Clear ca...
Mavericks Cache Cleaner is an award-winning general purpose tool for OS X. MCC makes system maintenance simple with an easy point-and-click interface to many OS X functions. Novice and expert users... Read more
OneNote 15.2.2 - Free digital notebook f...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
Apple Configurator 1.6 - Configure and d...
Apple Configurator makes it easy for anyone to mass configure and deploy iPhone, iPad, and iPod touch in a school, business, or institution. Three simple workflows let you prepare new iOS devices... Read more
SpamSieve 2.9.16 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
OS X Server 3.2.1 - For OS X 10.9.5 Mave...
OS X Server is the next generation of Apple's award winning server software. Designed for OS X and iOS devices, OS X Server makes it easy to share files, schedule meetings, synchronize contacts, host... Read more
Apple Security Update 2014-004 - For OS...
Apple Security Update is recommended for all users and improves the security of Mac OS X. For information on the security content of this update, please visit this website: http://support.apple.com/... Read more

Latest Forum Discussions

See All

Down Among the Dead Men (Games)
Down Among the Dead Men 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Avast! Take to the high seas in a fully interactive piratical tale of broadsides and buccaneers. From author Dave... | Read more »
Sling Adds Chromecast Support Through Sl...
Sling Adds Chromecast Support Through Slingplaye​r Mobile Apps Posted by Jessica Fisher on September 18th, 2014 [ permalink ] | Read more »
How to Completely Delete Your iPhone’s C...
The iPhone 6 is out tomorrow, and plenty of people are excited about it. So much so that they’re planning to – or already have – traded in their old iPhone to go towards it. The thing about trading in hardware is it’s very important to make sure... | Read more »
Dragon Quest I Review
Dragon Quest I Review By Andrew Fisher on September 18th, 2014 Our Rating: :: THINE QUEST AWAITETHUniversal App - Designed for iPhone and iPad Its historical significance aside, Dragon Quest 1 is a fun, campy, difficult, thoroughly... | Read more »
It Came From Canada: Overkill 3
Overkill 3 is like every trope of big modern gaming rolled into one. It’s a sequel to an action-packed military shooter. It’s flashy and scripted and flaunts its sophisticated graphics. And it’s a mobile game with a heavy emphasis on in-app... | Read more »
New Modes and Leader Boards in Update fo...
New Modes and Leader Boards in Update for Rules! Posted by Jessica Fisher on September 18th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
TwistedRun Review
TwistedRun Review By Rob Thomas on September 18th, 2014 Our Rating: :: DON'T TWIST YOUR ANKLE!Universal App - Designed for iPhone and iPad TwistedRun is kind of like running up a giant curly fry into the sky. Or maybe that was just... | Read more »
Scope Review
Scope Review By Jennifer Allen on September 18th, 2014 Our Rating: :: LOCATION AWAREiPhone App - Designed for the iPhone, compatible with the iPad Want to easily find photos from around the world based on their location? Scope is a... | Read more »
HipstaFox Review
HipstaFox Review By Jordan Minor on September 18th, 2014 Our Rating: :: FANTASTIC MR. FOXUniversal App - Designed for iPhone and iPad HipstaFox is a great single that makes players long for the whole album.   | Read more »
Ninja Raft (Games)
Ninja Raft 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: ** Special Launch Price ** "Ninja Raft is definitely the game to play if you’re into Tower Defense games and want to play something... | Read more »

Price Scanner via MacPrices.net

Save up to $300 on the price of a new Mac wit...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
13-inch 2.8GHz Retina MacBook Pro available f...
B&H Photo has the new 2014 13″ 2.8GHz Retina MacBook Pro on sale for $1699.99 including free shipping plus NY sales tax only. They’ll also include free copies of Parallels Desktop and LoJack for... Read more
16GB iPad Air on sale for $449, save $50
Walmart has the 16GB iPad Air WiFi on sale for $449 on their online store for a limited time. Choose free home shipping or free local store pickup. Their price represents a $50 savings over standard... Read more
13-inch 256GB MacBook Air on sale for $1099,...
B&H Photo has the 2014 13″ 1.4GHz 256GB MacBook Air on sale for $1099.99. Shipping is free, and B&H charges NY sales tax only. Their price is $100 off MSRP. Read more
Toshiba Introduces TransMemory ID High-Speed...
Toshiba’s Digital Products Division (DPD), a division of Toshiba America Information Systems, Inc., today introduced the TransMemory ID USB 3.0 Flash Drive, a simpler storage solution for people who... Read more
New iPads and OS X Yosemite Release Coming Oc...
The DailyDot’s Micah Singleton reports that Apple is planning to hold its next product announcement event on Oct. 21, at which it will unveil the iPad Air 2 and iPad mini 3 and release a final build... Read more
Logitech Bluetooth Multi-Device Cross-Platfor...
Logitech has an enviable track record of making some of the best computer keyboards and mice. At least in my estimation, the best freestanding keyboards I’ve ever used have been Logitech units,... Read more
Roundup of Apple refurbished iPad Airs and iP...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
Sprint offers 16GB iPad mini for $199.99 with...
Sprint is offering 1st generation 16GB iPad minis for $199.99 with a 2-year service agreement. Standard MSRP for this iPad is $429. Their price is the lowest available for this model. Read more
2.5GHz Mac mini remains on sale for $549, sav...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more

Jobs Board

Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.