TweetFollow Us on Twitter

Leap of Faith

Volume Number: 19 (2003)
Issue Number: 3
Column Tag: Leap of Faith

Leap of Faith

Why and how we switched from Carbon to Cocoa

by Steven Frank

A Dilemma

From the beginning, we were excited. A new Mac OS based on Unix! We loved the look and feel of Mac OS, and we loved the stability and standards of Unix, and the thought of the two combined was so wonderful that it was as if a choir of angels had descended with baskets of fine Belgian chocolates and sweet-smelling flowers on down pillows. That is to say, we liked the idea very much. But we also realized the magnitude of the change, and that it wasn't going to happen overnight.

After the release of Mac OS X we found ourselves, like many other Mac developers, confronted with a dilemma. We had two successful applications under our collective belt and, being serious Mac OS X fans, we knew beyond a doubt we wanted to upgrade them to Mac OS X native status. Our dilemma was, should we quickly port our applications using Carbon or essentially start them over in Cocoa?

Time being of the essence in those early days, we started ripping out the legacy code, and went the Carbon route. The Wild West-like frontier of Carbon was a little rough at first, but as Carbon itself was revised and finalized, it became mostly painless to get Classic code running on Mac OS X. Apple's Carbon team did a truly commendable job in making so many old applications run on a brand-new operating system architecture with so few changes. However, when the dust settled, it became apparent that our newer application, Audion, had fared much better in the transition than our older application Transmit.

Transmit, a graphical File Transfer Protocol (FTP) client, was originally written in 1996-1997, targeting Mac OS 7.5. Open Transport was still something new on the horizon. The Appearance Manager had not yet made its debut. Transmit was the first application I had ever written in C++ and my first PowerPlant application, and as such had a number of, shall we say, fascinating design decisions that, to be honest, are too embarrassing to mention.

As the Mac OS evolved, so did Transmit. Code was added to decide between MacTCP and Open Transport networking at runtime. More bridging code decided whether Mac OS 8 Appearance Manager widgets could be used, or whether backwards-compatible work-alikes were needed.

Mac OS X was unkind to our four year old code, and rightly so. Little bugs that had slipped past us, due to the lax nature of earlier OS versions, brought Transmit down in a flaming wreck on Mac OS X. I was grateful (no, really) to have these bugs brought to my attention, but it was clear that the code was due for an overhaul.

I had been learning Cocoa in my spare cycles for some time, and I very much liked what I saw. Here was a framework that was well designed, extensible, and very easy to use. The more I learned about it, the more I liked. It seemed like a good way for us to embrace the future, and bury that old code once and for all.

In March 2002 I decided to take the plunge, and started a skunkworks rewrite of Transmit in Cocoa that would later become the official Transmit 2 project with a three-person strong development team. What follows are some of the lessons we learned along the way.

Learning To Speak

One of the first decisions we faced was which language to use. Cocoa code can be written in either Objective-C or Java. My being more familiar with C and C++, as well as having an existing codebase written in those languages pretty much sealed the deal for Objective-C.

I've been surprised by the overwhelming reluctance of some of my fellow developers when it comes to Objective-C. It's a phenomenon I, as of five minutes ago, call "bracket shock". Developer sees what appears to be straight C code, but is confused by inexplicable brackets. Developer runs screaming back to their currently preferred language.

Objective-C is a very easy language to learn and surprisingly powerful once you understand its nuances. If you currently know ANSI C, and are at least familiar with object-oriented programming concepts, you can learn enough in one or two days to grope your way through your first project. I'm not exaggerating. You just have to get over your bracket shock.

In fact, to help you out, here are the only things a practicing C programmer really needs to know about Objective-C to get started:

    1. It's just C, but with object-oriented programming facilities.

    2. Those brackets surround method invocations. They're essentially just fancy function calls.

    3. Method arguments have names indicating their purpose.

    4. A hyphen indicates a method that is invoked on an instance of a class. A plus sign indicates a method that is invoked on the class itself.

Come to grips with those, then bounce back and forth between sample code, tutorials, and developer documentation, and you will be a master Objective-C programmer in less time than it would take you to complain about Objective-C's syntax. Apple provides a great introduction called "The

Objective-C Programming Language", located at: http://developer.apple.com/techpubs/macosx/Cocoa/ObjectiveC/index.html

Make no mistake though, the best way to write Cocoa code is not to hurriedly shoehorn in your old C++ code. Beyond the syntax itself, Objective-C code has its own style. There are "traditional" ways of naming methods and their arguments. I spent some time fighting this, and eventually realized I was just making things more difficult for myself. If you follow the traditional styles, other Objective-C programmers will be able to read your code and offer assistance. Learn about the Foundation types, especially NSString, NSArray, and NSDictionary, as these are workhorse classes that are used over and over and over again. Use these Foundation types instead of re-inventing your own container classes for the n-th time. It will make things easier. After a while, it gets under your skin and you will start to subconsciously realize when you are not doing things "the Cocoa way". As a general rule for Cocoa newcomers, if you ever find yourself saying, "There's got to be an easier way to do this," you are almost certainly right, and you should go find out what it is before continuing down your current path.

Keep in mind that learning additional programming languages beyond your comfort zone exposes you to new ideas and concepts, and makes you more employable. Go on! Try it! I had bracket shock at first too, but Objective-C is now among my favorite programming languages.

Dealing With Humans

Pesky humans! As developers, we write all this amazing and wondrous code, and then we have to figure out a way to expose the greatness of it all to plain-old ordinary human beings.

Fortunately for us, Apple has spent hundreds of thousands of dollars figuring out really good ways for us to do so, and they're giving this research away to us, for free, in the form of the Human Interface Guidelines, available online at: http://developer.apple.com/techpubs/macosx/Essentials/AquaHIGuidelines/index.html

Have you actually ever read the Human Interface Guidelines (HIG)? Be honest. I won't tell. What you need to know, as a Classic Mac OS programmer considering making the move to Mac OS X, is that these guidelines have changed for Aqua. In some areas, they've changed a lot.

When is it appropriate to use sheets? Drawers? Toolbars? The "metal" appearance? "Whenever it looks cool" is not the right answer for any of these.

If you have directly ported your Mac OS 9 interface to Mac OS X, it's going to look weird. You may not think it looks weird, but your Mac OS X users, even if they don't know exactly why, will feel a vague sense of unease when using your application. Something, they'll think, looks off. They'll find themselves compelled to use a different application that doesn't give them that feeling. You can get away with a sloppy interface on Windows, but on the Mac OS, it's cause for a public flogging.

In Mac OS X, the default fonts and font sizes have changed. The recommended spacing between controls has changed. Sheets are generally preferred over dialogs, but not always. The location of the Preferences and Quit menu items has changed. There are specific guidelines for designing your application's icon. Whitespace is preferred over separator lines. Visual hierarchy is preferred over group boxes. Do your windows avoid overlapping the Dock when zoomed?

If nothing else, you owe it to yourself to read the HIG section "Checklist for Creating Aqua Applications" which will give you a nice summary of the rest of the material. While it is obviously important that your application perform its tasks quickly and reliably, never underestimate the weight placed by users on your application's appearance, familiarity, and usability. That's true no matter which version of Mac OS you're developing for.

Environmental Concerns

It used to be that if you wanted to write a Cocoa application, you had to use Apple's Project Builder. Since then, Metrowerks has updated CodeWarrior to also support development with Cocoa.

Since CodeWarrior's Cocoa support was not completely available at the very beginning, I ended up learning Project Builder, and it's now my development environment of choice. Unfortunately, never having used it, I'm not qualified to talk to you about CodeWarrior's Cocoa support. But, I can tell you what I like about Project Builder.

First and foremost, I love Project Builder's integration with the gdb debugger. If you are not a Unix aficionado, you may not be familiar with gdb. At the surface, setting breakpoints within Project Builder and so forth is as easy as any other IDE, but if you're willing to spend a little time learning about gdb and delving into the debugging console, you can do some phenomenally advanced debugging. It is possible, just as an example, to set a programmatic breakpoint in a loop that stops execution, dumps the state of a few variables and then resumes, all automatically.

I've also come to appreciate Project Builder's single window layout option. At first, it felt a bit foreign, but before long I was zipping around as fast as ever. Integration with the CVS source management system was another big plus.

One Cocoa-ism that tends to throw people coming over from Carbon is the significance of Interface Builder in the development process. At first glance, it appears to be just a user interface layout tool like PowerPlant's Constructor. It is used for that purpose, but its role goes much further. In Interface Builder, you actually describe relationships between GUI controls and living, breathing objects in your code. If you find yourself looking for a call that just doesn't seem to exist ("How do I get a pointer to that button object in my window?") the answer probably lies in Interface Builder. (In this case, connect the button to a member variable in the class that is looking for it; Cocoa will set its value at runtime.) Project Builder and Interface Builder are tightly integrated, which is another advantage to using Apple's IDE.

On the flip side, Project Builder (or rather gcc, the underlying compiler) does seem slower at compilation than CodeWarrior did. My personal opinion is that the speed factor is outweighed by Project Builder's integration and overall stability. In this case, if it's good enough for Apple's developers, it's good enough for me.

Development environments are like religions though, and I know better than to recommend either. Try all of the available environments and see what you like. You may even be a truly hardcore user and prefer the Terminal's command line for all your development needs. That's OK too. Use whatever works best for you. But, as I said in the section about Objective-C, don't be a stereotypical stubborn developer. Keep your mind open, and don't be afraid to try new things. You might just learn something.

Getting Some New Threads

The first real issue I encountered while rewriting Transmit in Cocoa was a fundamental change in the operating system's threading model. All well-behaved network applications use some sort of threading, since it's no fun to be locked out of the user interface while network activity is taking place, with nothing but the rainbow beachball to keep you company.

In the old world, Transmit used the Thread Manager, which implemented the moderately cheesy "cooperative threading" model. In cooperative threading, each thread of execution is responsible for transferring control to the next eligible thread whenever it feels the time is right. Cocoa's threading model (NSThread) is built atop POSIX threads, which are preemptive. In the world of preemptive threading, your threads must be prepared to be swapped in and out at the operating system's whim. This is much harder to get right, but it results in significantly more efficient threading. The kernel is even smart enough to often be able to execute threads on different processors on multiprocessor Macs.

The issue of threading is complicated by somewhat vague documentation on which parts of Cocoa are "thread-safe" and which are not. The very general consensus seems to be that it is best to avoid calling into the Application Kit from any thread other than the main thread. So how, for example, should worker threads update elements in the user interface?

Until 10.2, the answer was to use Cocoa's Distributed Objects (DO) mechanism to invoke a method on the main thread that would perform the update on the worker thread's behalf. Explaining how to do this correctly is another article in itself, but enough information exists on the net that careful web searching will reveal what you need to know.

Alternatively, there is a new call available in 10.2, which makes the whole business much easier: performSelectorOnMainThread in NSApplication. You simply choose which method ("selector" is a bit of Objective-C jargon) you want, and it will be scheduled to run on the main thread. Very handy. But if you use performSelectorOnMainThread, your program will only be compatible with 10.2 and up, so consider your audience carefully.

There's not enough room in this article to get into all the intricacies of threading, so I'll refer you to Apple's TechNote 2028, which compares the OS 9 and OS X threading models in greater depth: http://developer.apple.com/technotes/tn/tn2028.html

Making The Network Work

Around the Mac OS 8 timeframe, Apple introduced a new networking API called Open Transport, which still exists today in Mac OS X's Carbon layer. But there's another API worth considering when doing Cocoa development, which is the traditional BSD sockets interface. (BSD refers to the flavor of Mac OS X's underlying Unix subsystem.)

Open Transport views network connections as "streams". You set up a network "endpoint", and a handler function, and then sit back until you receive notification at your handler of network events, such as connections, incoming data, and so on.

The socket model, an older but arguably more popular metaphor, treats network connections similarly to file handles. You "open" them by connecting to the other side, then you read and write data, and eventually close them.

This is a gross oversimplification of the whole thing, of course. Many long and tiresome battles have been waged about the relative merits of sockets versus streams, and to get into that mess would be beyond the scope of this article. What's relevant here is that the availability of industry-standard BSD socket calls on Mac OS X opens up a wonderful world of third-party code, of which you can take advantage. In our case, I discovered LibNcFTP, a highly competent C library implementing most all facets of the FTP protocol.

With the threading model already in place, it was easy enough to drop in calls to LibNcFTP and let it do the heavy lifting as far as network activity was concerned. Having been originally written for Unix, the library compiled effortlessly on Mac OS X, and plugged into our project without much sweat at all. Nothing's perfect of course, and we sent our share of feedback to the very patient library developer, who dutifully incorporated our suggestions and patches into his own code. The availability of this library saved us probably weeks worth of re-inventing the wheel. I had a barebones version of Cocoa Transmit able to connect to FTP servers and get a file listing within the first week of development, and we were more than happy to pay the modest licensing fee asked for LibNcFTP. It would have been a much more rigorous ordeal to use this same library in a Classic Mac OS application.

Switching to Mac OS X and Cocoa allowed us to ditch our capable but sometimes fragile homegrown FTP implementation in favor of one that has been in continuous development and refinement for ten years. It was something that actually provided a visible benefit to our customers too, not just a gratuitous technical achievement.

Mach-o, Mach-o Man

If you are used to Classic Mac OS programming, you are probably at least remotely familiar with the PEF binary format. PEF is the native format of executable binaries on Mac OS 9. Mac OS X can load PEF binaries for backwards compatibility, but its native format is Mach-O. In fact, Mach-O is the only binary format that Project Builder's tool chain will generate.

Classic PEF binaries had the concept of code modules that could be "weak-linked" or "strong-linked". To very quickly summarize, if you wanted to call an operating system API that was present in one version of the OS, but not another, you could tell the linker to either weak-link or strong-link that reference. If strong-linked, your application would not launch unless that API was present. Instead, the Finder would display a (usually quite terse) error message about the missing API. If the same application was weak-linked to the API, the application would launch, but the function pointer for the missing API would be set to NULL. This allowed the programmer to check at runtime what capabilities were available. The downside was if you forgot to check first and jumped to a NULL API, your application would crash.

Under Mac OS X and Mach-O, by default, if you have calls to functions in the BSD subsystem that are not implemented on the OS version that your program is running on, the OS will abort launching your application and log the offending call into the Console. We quickly discovered this within ten minutes of sending out our first Transmit 2 beta release, as we started getting reports from about half the testers that it wouldn't launch on their computers. We finally determined that all of these testers were running Mac OS X 10.1 and we were all running 10.2.

The problem was we had called a BSD function that was implemented on 10.2, but not 10.1. The 10.1 users saw only a generic Finder error message ("The application has unexpectedly quit"), while the true cause could be found in the Console's log. The system had logged the exact name of the missing function, which lead us straight to the root of the problem. Once we added a runtime check for the function, and appropriate bridging code, everything was back to normal.

However, if you invoke methods in the Cocoa frameworks that are unimplemented on the running system, a message will be logged to the Console, but your program will continue execution. This can lead to insidious bugs that seem inexplicable, unless your user happens to be running with the Console open. (Hint: He or she isn't.)

The best way to check if a Cocoa method exists before calling it is to send a respondsToSelector: message to the target object, passing the method in question. It will return a Boolean value indicating whether the method is implemented.

It's also beneficial to read the release notes for the Cocoa frameworks with each new release of the developer tools. They will explain which functions are new to each version.

An extra tip to those using the Jaguar developer tools: Apple now provides a preprocessor macro to control the compatibility level of the Cocoa headers. In other words, if you want precompiled headers that contain only APIs present in 10.1, you can run the following Terminal command:

   sudo fixPrecomps -force -precompFlags -DMAC_OS_X_VERSION_MAX_ALLOWED=1010

Then, in the area labeled "Other C Compiler Flags" in the "GCC Compiler Settings" section of your Project Builder project's target settings, add:

-DMAC_OS_X_VERSION_MAX_ALLOWED=1010

After completing these two steps, you'll get compiler errors if you try to use a Cocoa feature that is not available in 10.1.

There are two more probably obvious bits of advice that can be gleaned from our experience:

    1. Always try running your application on a system that meets only your application's minimum requirements before sending it off to anyone. Before you say your program runs on 10.1, try it to make sure!

    2. If your users are reporting weird behavior in your Cocoa application that does not match your understanding of the world, the first place you should look is the Console log. The odds are high that there will be some sort of message that will give you a clue, if it doesn't lead you directly to the source of the problem.

You should be aware that the few short paragraphs above represent only a very light treatment of the Mach-O linking and loading process. For more in-depth information, I recommend reading Apple's "Mach-O Runtime Architecture" located at: http://developer.apple.com/techpubs/macosx/DeveloperTools/MachORuntime/index.html

Care Package

Another aspect of Cocoa and Mac OS X programming in general that Classic Mac OS programmers will want to familiarize themselves with is application packaging. The Classic version of Transmit was distributed as a single file with code in the data fork and GUI resources in the resource fork.

The preferred format on Mac OS X is the application package. This is a folder hierarchy organized in a specific, known way, containing your binary executable, application metadata, and any resource files your application uses. The entire folder structure is presented to the user as a single double-clickable application icon.

Project Builder will automatically package your Cocoa application, so this is generally not something you have to worry too much about. However, it is worth your time to understand the layout of an application package and the reasoning behind it. To this end, you should read the "Application Packaging" section of Apple's Mac OS X "System Overview", which can be found here:

http://developer.apple.com/techpubs/macosx/Essentials/SystemOverview/ AppPackaging/Application_Packaging.html

The Cocoa class NSBundle assumes most of the roles of the classic Resource Manager, automatically locating application resources by name and type. A significant benefit of the application package appears when it comes time to localize your application into another language. In a nutshell, a folder is added to your application package for each language that your application supports. The files within each of these folders are identical for each language, but their content is localized for that language. When you ask Cocoa to retrieve, for example, your Preferences window from your resources, it is smart enough to return the French version when running on a French system, the German version on a German system, and so on. You only have to maintain one build, and it will localize itself at runtime. If you've ever localized a Classic Mac OS application, you can appreciate how much easier this is than the previously required gyrations.

It's not uncommon for your more devoted users to do the dirty work of localization for you, before you've even started looking for a translator. Within days of Transmit 2's release, we received a set of fully localized French resources which we were able to simply drop into the project, rebuild, and add French localization to our list of features.

Before releasing your code into the wild, you should go to the Terminal and type man strip. This curiously worded command will give you probably more information than you want to know about the "strip" command, which can be used to remove debugging symbols from your code. Even in a "deployment" build, Project Builder appears to leave behind a lot of symbolic information that is not needed in a shipping project. This can bloat the size of your executable dramatically, often to two or three times more than its natural size. The man page will describe all of the available options in gory detail, but my favorite incantation is strip -S <filename> (note the capital S), which removes symbols related to debugging, but not things like function names. You'll need to run this command on the actual executable, located in the Contents/MacOS directory of your application package. Why would you want to leave behind function names? For crash logs, which I'll get to in just a moment. Using strip -S reduces the size of the Transmit 2 executable by about three megabytes, which is nothing to sneeze at. One thing to look out for, though - if you leave function names in your shipping executable, you do make it slightly easier for pirates and other nefarious types to find their way through your code and deactivate any copy protection or registration schemes you may have employed.

Inevitably, the day will come when one of your users will report that your application has crashed. Wouldn't it be nice if you could get some truly detailed technical information about the nature of the crash? Mac OS X makes it possible! The first thing your user can do to help you is to head to the preferences of the Console utility. There, under the Crashes tab, are two checkboxes: Enable crash reporting, and Automatically display crash logs. Have the user turn both checkboxes on, then try to reproduce the crash. If the application does crash again, a log window will automatically pop up, containing vital clues about what happened, including a call stack trace of all running threads. Best of all, it's very easy for the user to cut and paste this information into an email to you. Much easier than it ever was with MacsBug!

Because you took my advice and used strip -S, the function names will be present in the stack traces, and hopefully it will be obvious what happened. One caveat about the crash logs - they get appended to the bottom of the file each time, but when the log window appears, its scrollbar is always scrolled to the top of the file. If you're not paying attention, you may think a bug you have already fixed is reappearing, when in fact you have to scroll down to get at the truth of the matter. Be sure to advise your users of this too. The quickest way to get to the most recent crash log is to scroll all the way down to the bottom, then page up until you see a row of 10 asterisks (**********). This indicates the start of an individual crash log.

Precious Natural Resources

The most important thing you need to know if you decide to make the journey from Carbon to Cocoa is that you aren't alone. There are plenty of other developers in the same boat, and many who have already traveled the road ahead. Don't make the mistake of isolating yourself from these great resources!

Cocoa sample code is increasingly abundant. If you find yourself stuck on a particular API, try plugging its name into Google and see what you find. Odds are good that relevant information is just waiting for you to discover it.

Web sites dedicated just to Cocoa programming are popping up left up and right. Just to name a few: www.cocoadevcentral.com, www.stepwise.com, and my own www.cocoadev.com each provide a slightly different approach to the topic, and are all worth a visit.

There are at least two mailing lists on the topic, which are worth joining. You can join Apple's cocoa-dev list at http://lists.apple.com/mailman/listinfo/cocoa-dev. The macosx-dev mailing list, hosted by Cocoa gurus The Omni Group, tends

to delve a bit deeper into the technical: http://www.omnigroup.com/developer/mailinglists/macosx-dev/. It's not necessary to read every message on the list (although you'd certainly learn a great deal if you did). I have a Mail filter set up that saves each mailing list message as it arrives into a mail sub-folder. This provides me with an extensive archive of discussions that's easily searchable for those times when I'm just stumped. Almost always I find that my most pressing questions have already been asked. If you do find you need to pose a new question, please be careful to observe good netiquette when posting to the lists, or you may find yourself feeling somewhat unwelcome.

If you are brand new to Cocoa and looking for something in hardcopy, I enthusiastically recommend Cocoa Programming for Mac OS X by Aaron Hillegass. It was the first Cocoa book that I felt was truly accessible when I was just starting out.

Last but not least, don't underestimate the value of joining Apple's Developer Connection (ADC) at http://connect.apple.com/. Basic accounts are free, but for a nominal subscription fee you'll receive prerelease seeds of upcoming versions of Mac OS X, as well as access to developer technical support from actual Apple employees, and a wealth of other perks.

All of these resources came to our rescue over and over again as we came to grips with the brave new world of Cocoa. It would have taken us much longer to release the product if we had not been fully plugged-in to them. Don't go it alone!

The Outcome

You're probably wondering, after all that work, was it worth it? We started over with a blank page and worked for about six months to recreate something that, by and large, already existed. It seems hard to justify. It seems like a duplication of effort.

I can assure you that it was absolutely worth it.

Our users were almost universally delighted to see the Cocoa version of Transmit. They were loud and clear that the time we had spent in the rewrite had paid off in terms of stability and functionality. User interface elements, such as toolbars and tables, that were tough to implement in Carbon required very little effort in Cocoa. Our native threading and networking model took full advantage of Mac OS X's architecture, especially on multiprocessor machines, and paid off dividends in speed. Not only that, but we got a chance to apply four years of user feedback in a major re-design of the program's underpinnings. Transmit's code is now significantly easier to maintain as well, and adding new features no longer has that "hope I don't bump the house of cards" feeling that I know you've experienced at some point in your projects. I don't regret any part of the endeavor.

You (or your manager) may have qualms about the size of the Mac OS X market. All indications from this end are that it's growing and fast. We released Transmit 2 for Mac OS X only in October of 2002 and it is selling at least as well, if not better than the previous OS 9 versions. Although we still offer an older version, 1.7, for our OS 9 users, we did not receive the torrent of "Where is Transmit 2 for OS 9?" email that we were expecting. In fact the people who are writing in about the OS 9 version seem to be almost universally indicating that it's only a stepping-stone until they get the chance to install Mac OS X.

Don't forget that Apple has decreed that new Macs will no longer be able to boot into OS 9. Whether you ultimately choose Carbon or Cocoa, the message is clear: migrate your code to OS X or become irrelevant. Mac OS X is the future of the Macintosh platform.

Moving to Cocoa isn't suitable or possible for everyone, and I can understand that. Every project has its own unique situation, scope, and requirements. But if you think there's even a slight chance you might be able to make the leap, you have my full encouragement to go for it, and hopefully this article will help you avoid some of the snake pits along the way. Good luck!


Steven Frank is the co-founder of Mac software renegade Panic, Inc. He was the original programmer of Transmit, an FTP client, and Audion, a digital audio player, as well as other smaller utilities. He can be contacted via email at stevenf@panic.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

FileZilla 3.51.0 - Fast and reliable FTP...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.51.0: Bugfixes and minor changes: Fixed import of... Read more
KeyCue 9.8 - Displays all menu shortcut...
KeyCue has always been a handy tool for learning and remembering keyboard shortcuts. With a simple keystroke or click, KeyCue displays a table with all available keyboard shortcuts, system-wide... Read more
AppCleaner 3.5.1 - Uninstall your apps e...
AppCleaner allows you to uninstall your apps easily. It searches the files created by the applications and you can delete them quickly. Version 3.5.1: Fixed a code-signing issue causing AppCleaner... Read more
A Better Finder Attributes 7.03 - Change...
A Better Finder Attributes allows you to change JPEG & RAW shooting dates, JPEG EXIF meta-data tags, file creation & modification dates, file flags and deal with invisible files. Correct EXIF... Read more
Postbox 7.0.33 - Powerful and flexible e...
Postbox is a desktop feature-stuffed email client, news application, and feed reader that helps you manage your work life and increase productivity. Now you can organize all your email accounts in... Read more
Adobe InCopy 16.0 - Create streamlined e...
InCopy is available as part of Adobe Creative Cloud for $52.99/month (or $4.99/month for InCopy app only). Adobe InCopy, ideal for large team projects involving both written copy and design work,... Read more
Steam 2.0 - Multiplayer and communicatio...
Steam is a digital distribution, digital rights management, multiplayer and communications platform developed by Valve Corporation. It is used to distribute a large number of games and related media... Read more
Adobe Lightroom Classic 10.0 - Import, d...
You can download Lightroom for Mac as a part of Creative Cloud for only $9.99/month with Photoshop, included as part of the photography package. The latest version of Lightroom gives you all of the... Read more
Adobe InDesign 16.0 - Professional print...
InDesign is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous InDesign customer). Adobe InDesign is part of Creative Cloud. That means you... Read more
Adobe After Effects 17.5 - Create profes...
After Effects is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects can make the impossible possible. Get... Read more

Latest Forum Discussions

See All

Genshin Impact Guide - Gacha Strategy: W...
If you're playing Genshin Impact without spending money, you'll always need to be looking for ways to optimize your play to maximize rewards without getting stuck in a position where you're tempted to spend. The most obvious trap here is the game'... | Read more »
Genshin Impact Adventurer's Guide
Hello and well met, fellow adventurers of Teyvat! Check out our all-in-one resource for all things Genshin Impact. We'll be sure to add more as we keep playing the game, so be sure to come back here to check for updates! [Read more] | Read more »
Genshin Impact Currency Guide - What...
Genshin Impact is great fun, but make no mistake: this is a gacha game. It is designed specifically to suck away time and money from you, and one of the ways the game does this is by offering a drip-feed of currencies you will feel compelled to... | Read more »
XCOM 2 Collection on iOS now available f...
The XCOM 2 Collection, which was recently announced to be coming to iOS in November, is now available to pre-order on the App Store. [Read more] | Read more »
Presidents Run has returned for the 2020...
IKIN's popular endless runner Presidents Run has returned to iOS and Android just in time for the 2020 election season. It will see players choosing their favourite candidate and guiding them on a literal run for presidency to gather as many votes... | Read more »
New update for Cookies Must Die adds new...
A new update for Rebel Twins’ platformer shooter Cookies Must Die is coming out this week. The update adds quite a bit to the game, including new levels and characters to play around with. [Read more] | Read more »
Genshin Impact Guide - How to Beat Pyro...
The end game of Genshin Impact largely revolves around spending resin to take on world bosses and clear domain challenges. These fights grant amazing rewards like rare artifacts and ascension materials for weapons and adventurers, but obviously... | Read more »
Moto Rider GO has received a huge update...
Moto Rider GO: Highway Traffic is a popular free-to-play racing game that initially launched back in 2017 and has since racked up over 100 million downloads. Today it has received a sizeable update that introduces several KTM and Husqvarna... | Read more »
ORDESA is a spooky interactive film that...
French studio Cinétévé Experience and ARTE have released interactive movie ORDESA for iOS and Android today. It arrives at the perfect time of year, telling a story about a mysterious haunted house that the viewer suddenly finds themselves lost in... | Read more »
Genshin Impact Guide - How to Beat Storm...
If you've followed our progression guide for Genshin Impact up to Adventure Rank 25, you have reached the point where you can face off against Stormterror on a weekly basis for some pretty sweet rewards. Beating this deadly dragon isn't as easy as... | Read more »

Price Scanner via MacPrices.net

AT&T offers the Apple iPhone 11 for $10/m...
AT&T is offering Apple’s 64GB iPhone 11 for $10 per month, for customers opening a new line of service, no trade-in required. Discount is applied via monthly bill credits over a 30 month period.... Read more
Apple’s 2020 11″ iPad Pros on sale today for...
Apple reseller Expercom has new 2020 11″ Apple iPad Pros on sale for $50-$75 off MSRP, with prices starting at $749. These are the same iPad Pros sold by Apple in their retail and online stores: – 11... Read more
Did Apple Drop The Ball By Not Branding Its C...
EDITORIAL: 10.21.20 – In the branding game, your marketing strategy can either be a hit or a miss and the latter is the case for Apple when it missed out on an opportunity to brand its “SE” series of... Read more
27″ 6-core and 8-core iMacs on sale for up to...
Adorama has Apple’s 2020 27″ 6-core and 8-core iMacs on sale today for $50-$100 off MSRP, with prices starting at $1749. Shipping is free: – 27″ 3.1GHz 6-core iMac: $1749, save $50 – 27″ 3.3GHz 6-... Read more
Apple’s 16″ MacBook Pros are on sale for $300...
B&H Photo has 16″ MacBook Pros on sale today for $300-$350 off Apple’s MSRP, starting at $2099. Expedited shipping is free to many addresses in the US. Their prices are among the lowest available... Read more
Apple has 2020 13″ MacBook Airs available sta...
Apple has a full line of Certified Refurbished 2020 13″ MacBook Airs available starting at only $849 and up to $200 off the cost of new Airs. Each MacBook features a new outer case, comes with a... Read more
These major wireless carriers will give you a...
Apple’s wireless partners are offering several deals on iPhone 12 pre-orders right now. If you’re willing to switch carriers, you can get a free iPhone 12 right now. Here’s where to take advantage of... Read more
4 day sale at Sams Club: Save $24-$29 on Appl...
Sams Club has Apple Watch Series 6 GPS models on sale this week for $24-$29 off Apple’s MSRP, starting at $374. Sale ends this Thursday, October 22nd: – 40mm Apple Watch Series 6 GPS: $374.98, save $... Read more
US Cellular offers Apple iPhone 12 Pro for $8...
US Cellular has the 2020 128GB iPhone 12 Pro available for $829 off MSRP for new customers signing up for an Unlimited data plan, or $5.66 per month. Cost of the phone is spread over a 30 month... Read more
Buy one Apple Watch SE or Series 6 at AT&...
Buy one Apple Watch SE or Series 6 at AT&T, and get $200 off the price of a second Apple Watch. One new line required, and price discounted reflected in bill credits over a 30 month period. The... Read more

Jobs Board

*Apple* Endpoint Engineer - Argonne National...
Apple Endpoint Engineer **Requisition Number:** **408932** **Location:** **Lemont, IL** **Functional Area:** **Information Technology** **Division:** **BIS\-Business Read more
Core *Apple* Computing Pro - Best Buy (Unit...
**786358BR** **Job Title:** Core Apple Computing Pro **Job Category:** Store Associates **Store Number or Department:** 001080-Lake Charles-Store **Job Read more
Department Manager- Tech Shop/ *Apple* Stor...
…their parents want, and our faculty needs. As a Department Manager in our Tech Shop/ Apple Store you will spend the majority of your time on the sales floor engaging Read more
Geek Squad *Apple* Consultation Professiona...
**782284BR** **Job Title:** Geek Squad Apple Consultation Professional **Job Category:** Store Associates **Store Number or Department:** 000140-San Carlos-Store Read more
*Apple* /Mac IT Support - Randstad (United St...
Apple /Mac IT Support **job details:** + location:San Francisco, CA + salary:$45 - $50 per hour + date posted:Thursday, October 8, 2020 + job type:Contract + Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.