The Ultra-Groovy LString Class

by John C. Daub, Austin, Texas, USA

An introduction to the PowerPlant-way of working with strings

Hello, World!

Most software developers have been working with strings since they wrote their first program - that's what "Hello World!" is all about. To facilitate working with strings many libraries of utility functions have been written. Some people have their home-brewed string libraries, while others utilize third party libraries or use the libraries provided in Standard C and C++. These solutions are well and good, but they do not always translate very effectively into the world of Mac OS. Many of these offerings, like the Standard C and C++ libraries, are written to work with C-style strings - a sequence of characters terminated by a null character. But due to the Mac OS Toolbox's Pascal heritage, strings on the Mac are Pascal-style strings - a sequence of characters preceeded by a length byte which stores the length of the string. Consequently, a string library designed to work with Pascal-style strings is more valuable to the Mac OS software developer. Enter PowerPlant's LString class.

LString is a C++ abstract base class for working with Pascal-style strings. It provides means for converting strings to numbers and numbers to strings; obtain strings from numerous sources (characters, other strings, resources); copy, append, and compare strings; find, insert, remove, and replace substrings; and does so in a manner that respects the boundaries of Pascal-style strings, takes advantage of the C++ language, makes your code easier to read and understand, and most of all is easy and logical to use. The inherited classes LStr255, TString, and LStringRef provide the concrete means for working with strings in a manner very familiar to Mac OS software developers, so the learning curve for LString is not a steep one. And although LString is a PowerPlant class it can be used independent of the rest of PowerPlant; feel free to use it in all of your Mac OS software development efforts.

If LString sounds good to you, then please read on. In this article I hope to provide you with a good overview of what LString provides, and illustrate how it will make your software development efforts easier. Along the way I'll also show you a few of the really cool and groovy power-user features of LString. But don't worry! Those power-user features are so easy to use that you'll be an LString-Warrior before you know it!

First, Some Background

Before I go any further, I want to make sure that we're on the same grounds of understanding just what a string is, and what the differences are between the various types of strings. If you already understand what the different types of strings are, feel free to skip ahead to the next section.

Simply put, a string is a sequence of characters. This sentence is an example of a string.

A C-style string is an array of characters (char*). The internal representation of the string has a null character ('\0') at the end, to signal the end of the string, so the amount of storage required for the string is one more than the number of characters in the string. Due to the use of the null terminator, there is theoretically no limit to the length of a C-style string, but you must scan the entire string to determine the length of the string (the C standard library function strlen() can be used to determine the length of the string). So the string "Hello, World!" contains thirteen characters, but at least fourteen bytes must be allocated to hold that string.

A Pascal-style string is also an array of characters (unsigned char*). Like a C-style string, a Pascal-style string also requires one more than the number of characters in the string for storage. However unlike a C-style string (and this is the defining and differentiating characteristic) there is no null terminator at the end of the string; instead, the first byte of the string is used to store a count of the number of characters in the string. You do not need to scan the entire length of the string to determine its length - you can merely examine the first byte (length byte) of the string. Also unlike a C-style string, a Pascal-style string does have a limit; this limit is determined by the number of bytes allocated in the unsigned char* array (e.g. unsigned char[256] would allow a string up to 255 characters). As a Pascal-style string "Hello, World!" still contains thirteen characters and also needs at least fourteen bytes for storage, but the internal representation of the string is different. Finally, when specifying a Pascal-style string constant, they are typically prefaced by a \p to tell the compiler to treat this string as a Pascal-style string (e.g. "\pHello, World!" would be the actual way to represent our example string as a Pascal-style string). Figure 1 illustrates how the internal storage of the "Hello, World!" string differs as a C-style string and a Pascal-style string.

Figure 1. String internal representations.

In Figure 1, each column represents a byte in the array (note we start at zero, like any array). The top row is the byte count, the middle row is the C-style string, and the bottom row is the Pascal-style string. Notice that both string styles require the same amount of storage (fourteen bytes). The C-style string places a null terminator in the last byte (although it looks like two separate characters \0 is just a special single character). When the string is read in, characters are read one by one until the null terminator is reached. If we wanted to find the length of the C-style string we would scan the string, starting from the beginning, counting each character as we go along until we reach the null terminator (this is what strlen does). The Pascal-style string places the length of the string in the first byte of the array (in this case the number thirteen, not "13" as a string or character). When the string is read, the first byte is checked for the length, and then exactly that many characters are read. If we wanted to find the length of the string, we check the first byte (string[0]).

Both styles of strings have their strengths and weaknesses. C-style strings can be of an arbitrary length whereas Pascal-style strings tend to have a more fixed size. C-style strings also have more overhead involved in determining the length of the string (a function call and walking the entire string), but you can find the length of a Pascal-style string with a simple check of the length byte.

On the Mac OS, most strings are Pascal-style strings (since the OS and toolbox were originally written in Pascal). To more easily represent and identify strings, and provide a simple means for defining strings of different lengths, MacTypes.h (formerly Types.h) typedefs some arrays of unsigned char's. The most popular version is a Str255, which is an array of 256 unsigned char's. There are others (Str63, Str32, Str15, StringPtr, ConstStr255Param - see MacTypes.h for a complete listing), and although Str255's are the most commonly used, the discussions in this article apply to any of these type(def)s. The Mac OS can also have raw text runs (e.g. 'TEXT' resources, TERec, etc.), and you can use C-style strings as well. The only time you are "forced" to use a Pascal-style string is when you interact with the Toolbox. If you wish to use C-style strings otherwise, you are very welcome to do so, especially if you are more familiar with the C Standard Library. Furthermore, the Toolbox provides some Pascal to-from C string conversion routines (c2pstr and p2cstr are in the Universal Header TextUtils.h ), and even provides C-glue routines that are glue routines to Toolbox functions that take C-style strings as arguments instead (look for the symbol CGLUESUPPORTED throughout the Universal Headers).

But as most Mac OS software development sooner or later requires you to interact with the Toolbox, most people find it easier to use Pascal-style strings all the time (also avoids the constant overhead of back and forth conversions). Due to this preference is why PowerPlant offers a great solution in LString. Let's now take a look at what exactly LString has to offer.

What's in There?

The LString class (and all of the classes and material I'll discuss here) can be found within the PowerPlant folder of the Metrowerks CodeWarrior Professional product. Specifically within the files LString.cp and LString.h. If you own CodeWarrior Professional, go ahead and open up those two files and look over them. I don't expect you to necessarily understand what's in there right now, but give them a look over so you can know what I'm talking about. You might also find it handy to refer to the sources as I refer to various parts of it so you can see how all of this fits together. For reference, I am writing this article using CodeWarrior Pro 4 and a version of LString that should be part of PowerPlant v1.9.3 (which will be released as public netborne update to Pro 4, and should be available by the time you read this article).

LString

LString is an abstract base class for working with Pascal-style strings. It defines almost all of the functionality that one would need for working with Pascal-style strings. LString also works to take advantage of the C++ concept of overloading. First many of the methods are overloaded to work with many data types (all built-in data types, both signed and unsigned, including floating point types; C-style strings; Pascal-style strings; FourCharCode; a Handle to text; other LString objects). Second, many of the methods are also offered as operator overloads, were logical, to make it easier for you to utilize these methods in your code. For example, operator += is the same as the Append() method. LString also defines some public methods as static so that non-LString objects can take advantage of some commonly needed string manipulations like copying and appending.

LString is designed to be clean, efficient, and work within the boundaries of the Mac OS and the Pascal-style strings utilized therein. As noted earlier, MacTypes.h defines different types of Pascal-style strings, like a Str255 or a Str63. Due to this ability to vary in storage length, any time length of string and/or storage is relevant to the functionality, LString always requires this information be provided, but typically also provides a default towards a Str255 as this is the most commonly used type. Furthermore, since Mac OS Pascal-style strings have 255 characters as the upper limit for strings (hence the Str255), LString always enforces this upper boundary where appropriate. If utilized correctly, LString should alleviate fears and eliminate the problem of array boundary overflows.

Although PowerPlant is a Mac OS-only framework, it does try to do what it can to aid those that might be using PowerPlant in a non-Mac context such as porting your Mac OS-based application to Windows. Some LString methods are only available under Mac OS (due to their nature), and techniques are provided for development environments that might not fully understand Mac OS conventions. For example, the traditional way to obtain the length of the string is to directly check the length byte. But since not all development environments support this method of access (of course CodeWarrior does), the LString::Length() method is provided as a certain means of always obtaining the length of the string.

As an implementation note, there is only one data member in LString: mStringPtr. mStringPtr is a StringPtr which points to your Pascal-style string. Note that the actual storage for the string is not part of LString. Without this sort of design, neither TString nor LStringRef could exist (I'll discuss these classes later in the article). So does this mean that you always have to allocate your own storage for your string? Not at all, as this is the purpose of LStr255.

LStr255

LStr255 inherits from LString. You can find the declaration of LStr255 in LString.h and definition in LString.cp. If the name of the class looks familiar to you, this is intended. The design of LStr255 is to replicate the functionality of a Str255, but with lots of extras. The great part is an LStr255 can be used almost anywhere a regular Str255 is used and in the same manner. Furthermore an LStr255 inherits all of the functionality of LString, plus it provides the actual storage for the string itself (the mString data member) so you do not have to.

Listing 1 demonstrates a typical set of actions that one might perform on a string. All of that work and code just to concatenate two strings. Listing 2 shows the same code but written using LString. Don't worry if you do not understand everything that is going on in Listing 2 because I'll cover it all in coming sections.

As you can see comparing Listing 2 to Listing 1, the same result is accomplished but Listing 2 contains a lot less code and is much easier to read. This just scratches the surface of what LString can do.

Two usage notes. First, when you are using LStr255 objects and viewing them in a debugger, you will actually see two instances of your string data within the LStr255 object. One of these will be from mStringPtr and the other from mString. Why do you see two strings and why are they always in sync? Why not just have one string? Remember that mStringPtr is just a pointer to your actual storage for your string, mString; rather, mStringPtr points to mString. This is how things are designed and it's all OK, don't worry about it. However if they are not in sync, you might want to investigate as this could be signaling a problem. Second, beginning with the next section and continuing for the remainder of the article, I will be using LStr255 objects in all code listings because LStr255 is the most commonly used type of LString. Do remember that what applies in those listings will generally apply to other LString derivatives as well, like TString and LStringRef.

TString

TString is a templatized version of LString. It allows you to utilize the power and functionality of LString upon any Pascal-style string type (Str255, Str63, Str15, etc.). Use of the class is exactly like using LStr255, except that you instantiate your object through normal C++ template instantiation mechanisms. Listing 3 is a rewrite of Listing 1 using TString. Note as well its similarity to Listing 2.

LStringRef

LStringRef is a newcomer to the LString family (it was introduced in PowerPlant v1.9.1, post CodeWarrior Pro 3). LStringRef provides you with a means to obtain the functionality of LString and use it to manipulate a string that you do not have ownership of. Unlike LStr255 and TString, LStringRef does not contain storage for the string itself; mStringPtr points to a string allocated elsewhere. For example, this can be used to change a string that is part of some data structure. Listing 4 demonstrates the use of LStringRef to change the filename in an FSSpec from whatever it originally was to "Hello File! copy".

Basic Features

Now that you've been introduced to the LString family and seen a little of what LString can do, it's now time to dig through the lines of code in LString.cp and LString.h to really see all that LString has to offer. By the way, do make sure you also read through LString.h as many of LString's functions are declared inline in the header file.

Object Construction

If you look through the LString sources, you'll notice that there is only one LString constructor. That's all that LString needs as it performs the core setup of the class's functionality. Where the constructors are really needed is within the subclasses. Look at the number of constructors there are for LStr255! And look what you can do with all of those constructors as well. You can create your LStr255 from: another LStr255, another LString, a Pascal-style string, a C-style string, an arbitrary string of text, a single character, data within a Handle, from a 'STR ' or 'STR#' resource, from a long or short integer, a FourCharCode, and from floating point values (long double). Wow! That covers just about every and any way you might want to create your LStr255 object.

If you look at the implementation of most of those LStr255 constructors, you'll see many of them call the Assign() method. Assign() assigns the given value to the LString object. Just as the constructors use Assign(), you are free to use Assign() as well when you wish to assign a value to your LString object. Furthermore, as a logical use of C++, you can see in LString.h that the assignment operator (operator =) has been overloaded with just as many combinations for those of you that prefer the use of operators in logical situations. Listing 5 demonstrates the many ways Assign() can be used.

Listing 5: The Many Faces of Assign()

Each line group produces the same result of creating an LStr255
object and giving it a string of "Hello, Assign!".
// Create and assign by initialization
LSt255 initString("Hello, Assign!");
// Create and assign by Assign()
LStr255 assignString;
assignString.Assign("\pHello, Assign!");
// Create and assign by assignment
LStr255 assignmentString = assignString;

String Manipulation

Now that you have created your LString and given it some text, you will probably want to do something with the text in that string. This functionality is what LString tends to be used for most, and within this subset lies the use of Append().

Append() appends a given value to an LString object. What can be appended is again just about anything (see LString.h for a complete list). As with Assign() and operator =, so with Append() and operator +=. You'll probably find yourself using operator += a great deal as it's so simple to type and makes your code so much easier to read. One issue to note with operator += (and perhaps other overloaded functions in LString) is that depending what you are trying to append you may receive compiler errors about an ambiguous access to an overloaded function. For instance, the following line of code will generate this error because the compiler cannot determine if you intend 1 to be treated as char, unsigned char, long, or short:

theString += 1;

If you receive this compiler error, all you need to do to resolve it is apply a static_cast (or C-style cast) which will tell the compiler explicitly how you wish the value to be treated:

theString += static_cast<SInt32>(1);

In addition to member functions for appending, LString also provides some global string addition operators (operator +). They are not LString member operators, but do act upon LString objects. These operators concatenate LString objects with: another LString object, a pointer to a string, or a character. The result of the addition is an LStr255 object. You can find these operators declared about mid-way through LString.h and defined near the bottom of LString.cp.

Finally, what would string manipulation be if you could not compare strings! You will find in LString.h a boat-load of global comparison operators that let you do just about any sort of string comparison you can think of: equals (operator ==), not equals (operator !=), greater than (operator >), less than (operator <), greater than or equals (operator >=), and less than or equals (operator <=). Listing 6 demonstrates the many ways you can manipulate strings with LString.

Utilities

Rounding out the basic features of LString are some utility functions. They fall into two groups: object-related and public.

The object-related utilities are utilities that are class member functions and only behave in relation to their associated LString object. These are methods like: Length(), which returns the string length as an UInt8; ShortLength() which returns length as an SInt16; LongLength() which returns length as an SInt32 (the different return types are to ease places where you need the string length but do not wish to typecast to match a function parameter or avoid an implicit arithmetic conversion); GetMaxLength(), to return the maximum length the string can be; TextPtr() and ConstTextPtr() to return a Ptr (or const Ptr) to the raw text (avoids those ugly (Ptr)&theString[1] situations, as was used in Listing 1); operator [] to allow access to individual characters in the string, just like you could with a basic array. Listing 7a illustrates the use of these utilities.

The public utilities of LString are a small group of static methods, publicly available for calling by pretty much anyone anywhere in your program (within reason, of course). These methods handle the most common string manipulations like: CopyPStr(), to copy one Pascal-style string into another Pascal-style string (e.g. Str255 to Str255); AppendPStr(), for a static version of LString::Append(); CStringLength() for obtaining the length of a C-style string with an upper limit of 255; FourCharCodeToPStr() and PStrToFourCharCode() for converting a FourCharCode (y'know, 'TEXT', 'PICT', 'PPob') to a Pascal-style string and back again; and FetchFloatFormat() and StringToLongDouble() to aid in some quick floating-point conversions. Listing 7b presents a display of these utilities' features.

Power Features

In addition to the basic functionality's discussed above, LString has some features for the power-user that help to round out the practicality of the class. If you consider yourself a beginner to LString, you should still give these power-features a look over as using these power-features is not difficult, and you can be a power-user in no time. The substring manipulations you may or may not use every day, but the "typecasting" abilities you'll find indispensable.

LString's ability to manipulate substrings provides you with the capability to perform substring searches, copies, and changes to that substring. In fact, you might even be able to create your own Find dialog using these features. The search functionality in LString allows you to: Find(), locate where a substring starts within the string; ReverseFind(), locate the position of a substring starting from the end of the string; to see if a string BeginsWith() or EndsWith() a specified string; find where the string starts within another string either from the beginning, FindWithin() or from the end, ReverseFindWithin(). In performing these searches, a comparison of text must of course be done. LString::ToolboxCompareText() is provided as the default mechanism for comparing the text; it uses the Toolbox CompareText() routine. If you do not wish to use the default comparison mechanism, you can specify your own CompareFunc via SetCompareFunc() to change it to whatever you would like. Of course after you have found your substring, you might want to do something with it. If you would like you can Insert() a string into your LString object, Remove() a substring from your object, or Replace() one substring with another. Or if you would just like to make a copy, operator () has been overloaded to provide you with an easy way to perform this copy. Listing 8 illustrates LString's substring manipulation features.

What I think is one of the niftiest features of LString is, as I like to call them, the typecasting operators. These are a series of operator overloads that fake the appearance of a typecast to allow your LString object to be flexibly used in many situations. You can find the operators listed near the top of the LString declaration in LString.h. These operators include: StringPtr, ConstStringPtr, SInt32, double, long double, and FourCharCode. When one of these operators is applied to the LString object, it converts the string into the "requested type" and returns the conversion. That is, apply operator SInt32 and the string is converted to a long integer and that long integer returned. The way to apply these operators is just like a typecast, but it's not really a typecast; it's technically an application of that operator, but the implementation and application of that operator simulates a typecast for ease of use and improved code readability. Furthermore, when attempting to resolve types, the compiler can implicitly apply these operators to the LString object for you. Look back at Figure 2 and notice that we passed our LStr255 object directly to DrawString? Listing 9 should clarify how all of this works.

Listing 9: Typecasting Operators

// Create our string (FIXEDDECIMAL comes from fp.h)
LStr255 theString(3.14, FIXEDDECIMAL, 2);
// Convert it and do some math (the static_cast technically
// isn't necessary, but here for illustration. Note that it
// looks like a typecast, but if you watch the code execute
// you'll step into operator double().
double number = static_cast<double>(theString);
number *= 2;
// Convert back to a string. Note there is no operator =
// for floating point variables. This is because of the
// need for extra information.
theString.Assign(number, FIXEDDECIMAL,2);
// Draw onscreen. Note the implicit operator call to
// operator StringPtr.
::DrawString(theString);

PowerPlant uses this technique of typecasting operators throughout the framework as a handy way to allow your objects to be treated as more basic Toolbox types for increased flexibility and seemlessness between PowerPlant, the Toolbox, and your code. See the use of operator Handle and operator Ptr in UMemoryMgr classes for another set of examples. Also, if you have access to the Scott Meyers book More Effective C++, read Item 5: Be wary of user-defined conversion functions. Scott labels the above technique implicit type conversion operators and points out the various strengths and weaknesses of the above technique.

Is There A Downside?

As great as LString is, there are certainly a few downsides. There may be others, but these are the big ones in my book. First, if you don't like Pascal-style strings or perhaps they're not as useful as a C-style string would be in a given situation, then of course LString would fall under the same roof. But if you use and/or like Pascal-style strings then this isn't much of an issue. Second, this code is C++. If you need Pascal-style string helper functions in C or another language then LString will not be of much use to you. Third, LString's are C++ objects. As an object it will have some additional overhead and memory requirements, at least compared to plain arrays (e.g. LStr255 vs. Str255). Furthermore because LString's are objects you cannot place them inside TArray's, except, as with all objects and TArray, as pointers to the object allocated via new. Due to this extra work, it's probably easier to just store plain Str255's in a TArray instead. But do not fret! If you must use Str255's you can still gain the features and power of LString via the LStringRef class applied to your Str255's.

Give It A Try

If you haven't already, give LString a try. The code listings should all function as compilable snippets. And since LString is mostly independent of the rest of PowerPlant (you may need to add the PP_Constants.cp file to your project as well), you can easily drop LString.cp into a basic Toolbox or console stationery and give them a try. Step through each listing in the debugger (make sure inlining is set to "Don't inline") and watch how things work. Watch where you go, how that pertains to the section material being discussed, and how they all fit into the larger picture. Just play around and experiment.

I hope that I've been able to give you a good introduction to the LString class and it's family of subclasses and utilities. It provides the Mac OS software developer with a fairly simple yet powerful class for working with Pascal-style strings. With the ability to create strings from almost any source, manipulate the contents of that string, and convert it for use in just about any situation, LString is a tool worth having in your programmer's toolbox.

I hope you find LString to be as ultra-groovy as I find it to be. But just in case, I'll borrow one from Dennis Miller: "Of course that's just me. I could be wrong."

John C. Daub can't think of anything snazzy to put in his bio other than 311's a great band to listen to while writing articles. If you'd like to contact John, you can do so at hsoi@metrowerks.com.

Community Search:

MacTech Search:

Software Updates via MacUpdate

MacFamilyTree 7.3.4 - 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

Yummy FTP 1.10.2 - FTP/SFTP/FTPS client...

Yummy FTP is an FTP + SFTP + FTPS file transfer client which focuses on speed, reliability and productivity.
Whether you need to transfer a few files or a few thousand, schedule automatic backups, or... Read more

VueScan 9.5.08 - Scanner software with a...

VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more

Iridient Developer 3.0.1 - Powerful imag...

Iridient Developer (was RAW Developer) is a powerful image conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more

Air Video Server HD 2.1.0 - Stream video...

Air Video Server HD streams videos instantly from your computer on your iPhone, iPad, iPod touch or Apple TV. No need to worry about converting or transferring files.
We took everything that was... Read more

Duplicate Annihilator 5.7.5 - Find and d...

Duplicate Annihilator takes on the time-consuming task of comparing the images in your iPhoto library using effective algorithms to make sure that no duplicate escapes.
Duplicate Annihilator... Read more

BusyContacts 1.0.2 - Fast, efficient con...

BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more

Capture One Pro 8.2.0.82 - RAW workflow...

Capture One Pro 8 is a professional RAW converter offering you ultimate image quality with accurate colors and incredible detail from more than 300 high-end cameras -- straight out of the box. It... Read more

Backblaze 4.0.0.872 - Online backup serv...

Backblaze is an online backup service designed from the ground-up for the Mac.With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more

Little Snitch 3.5.2 - Alerts you about o...

Little Snitch gives you control over your private outgoing data.
Track background activity As soon as your computer connects to the Internet, applications often have permission to send any... Read more

It seems like this month has been pretty big for wrestling. First Wrestlemania, then 2K has announces that they're releasing WWE 2K for iOS. It's a simulation-based WWE game where you'll get to play with several WWE superstars such as John Cena, ... | Read more »

How the Apple Watch Could Change the Fac...

The Apple Watch is still a ways out, but my previous musings on the wearable’s various features got me thinking: what might it be like a year after launch? Two years? Five years? What if it becomes a symbiotic part of the iOS framework to the point... | Read more »

Pie In The Sky: A Pizza Odyssey (Games)

Pie In The Sky: A Pizza Odyssey 1.0
Device: iOS Universal
Category: Games
Price: $2.99, Version: 1.0 (iTunes)
Description:
A game about delivering pizza. In space.
| Read more »

Chosen Gives Hopeful Singers, Songwriter...

If YouTube videos and reality TV shows like The Voice have taught us one thing, it’s that there are a lot of people out there who are anxious to show the world their talents. And if they’ve taught us a second thing, it’s that there’s an almost... | Read more »

Android's Popular OfficeSuite Now A...

Once only available for Android devices, OfficeSuite has finally landed on the app store. The Mobile Systems app lets you view, edit, create, and share Word, Excel, and PowerPoint documents as well as convert them to/from PDFs. It's touted as being... | Read more »

Warhammer: Arcane Magic is Coming Soon,...

Turbo Tape Games has announced that they're joining forces with Games Workshop to bring the turn-based strategy board game, Warhammer: Arcane Magic, to life on the iOS.
| Read more »

Fast & Furious: Legacy's Creati...

| Read more »

N-Fusion and 505's Ember is Totally...

| Read more »

These are All the Apple Watch Apps and G...

The Apple Watch is less than a month from hitting store shelves, and once you get your hands on it you're probably going to want some apps and games to install. Fear not! We've compiled a list of all the Apple Watch apps and games we've been able to... | Read more »

Appy to Have Known You - Lee Hamlet Look...

Being at 148Apps these past 2 years has been an awesome experience that has taught me a great deal, and working with such a great team has been a privilege. Thank you to Rob Rich, and to both Rob LeFebvre and Jeff Scott before him, for helping me... | Read more »

Price Scanner via MacPrices.net

Adobe Brings Powerful Layout-Design Capabilit...

Adobe today announced the availability of Adobe Comp CC, a free iPad app that enables rapid creation of layout concepts for mobile, Web and print projects. With Comp CC, designers can rough out and... Read more

Apple offering refurbished 27-inch 5K iMacs f...

The Apple Store is offering Apple Certified Refurbished 27″ 3.5GHz 5K iMacs for $2119 including free shipping. Their price is $380 off the price of new models, and it’s the lowest price available for... Read more

16GB iPad mini on sale for $199, save $50

Walmart has 16GB iPad minis (1st generation) available for $199.99 on their online store, including free shipping. Their price is $50 off MSRP. Online orders only.
Read more

The Apple Store has Apple Certified Refurbished 13″ 2.6GHz/128GB Retina MacBook Pros available for $979 including free shipping. Original MSRP for this model was $1299.
Read more

Save up to $600 with Apple refurbished Mac Pr...

The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Samsung Galaxy S 6 and Galaxy S 6 edge U.S. P...

Samsung Electronics America, Inc. has announced the Galaxy S 6 and Galaxy S 6 edge will be available in the U.S. beginning April 10, with pre-orders being accepted now.
“We have completely reimagined... Read more

13-inch 2.5GHz MacBook Pro (refurbished) avai...

The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free:
- 13″ 2.... Read more

MacTech is a registered trademark of Xplain Corporation. Xplain, "The journal of Apple technology", Apple Expo, Explain It, MacDev, MacDev-1, THINK Reference, NetProfessional, Apple Expo, MacTech Central, MacTech Domains, MacNews, MacForge, and the MacTutorMan are trademarks or service marks of Xplain Corporation. Sprocket is a registered trademark of eSprocket Corporation. Other trademarks and copyrights appearing in this printing or software remain the property of their respective holders. Not responsible for typographical errors.

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.