SpiralKit

Introducing SpiralKit

A little more than a year ago, I released my first iPhone application, Spiral by Digital Generalists.  After several updates and many happy customers, I’ve decided to release the drawing engine for Spiral as an open source framework through my company, Digital Generalists, LLC..

What Is SpiralKit

SpiralKit is a Quartz 2D-based drawing framework for iOS written in Objective-C. The framework enables ‘drawing’ on a UIView in an iOS application and ships with pen, highlighter, and eraser drawing effects.

The framework is built specifically to enable easily adding new effects, color spaces, and drawing algorithms in a modular fashion. If you want to provide a unique drawing effect, support of the CMYK color space, or a custom drawing algorithm, you can add such features to SpiralKit without having to modify the fundamental components of the framework.

Where to Find It

The project is hosted on GitHub at https://github.com/digital-generalists/spiralkit.

More Information

See the release post on the Digital Generalists site and the framework documentation for all information about using SpiralKit in your application.


Assurance

Introducing Assurance

Over the last few months, I’ve been working on a project and, today, I’m releasing the result of that project as Open Source Software. Assurance by Digital Generalists is an application that enables comprehensive file and folder comparison with tools to merge data on multiple operating systems.

Where to Find It

The project is hosted on GitHub at https://github.com/shelterbelt/assurance.

Inspiration for the Application

Over many years, I’ve collected a substantial library of electronic files ranging from simple text documents, spreadsheets from the very early ’90s, games, MP3s, videos, email archives, source code, etc… Because I had so much stuff, I had backups…plural. And backups of backups. And some stuff was on thumb drives because I needed it to be portable at some point. And some stuff eventually moved to newer machines, but I never deleted the copy on the older machine.

*sigh*

In short, I came to a point where I wanted to be able to compare the many copies of my digital archive, eliminate the redundant stuff, know where the latest version of everything was, and move things into a ‘repository-of-record’.

I easily could have purchased a tool to accomplish that task. There are highly-rated options available. Or I probably could have written a shell script that would have done the job from the command line.

However, I felt the problem presented a good opportunity to try out several software development frameworks and techniques I’ve been interested in learning more about. So I wrote Assurance instead.

What Is Assurance

Assurance is a cross-platform, client-only application written in Java that leverages both Spring and Hibernate with a Swing-based UI.

At it’s core, it is a tool to comprehensively compare and optionally synchronize the contents of files and directories.

While on first glance, Assurance may appear to be a good fit as a backup tool, it wasn’t really designed for those needs.  A backup tool should provide features like scheduling of jobs, conflict resolution, automated monitoring of the file system, one-click system restore, etc…  Assurance wasn’t built to solve those problems.  Assurance is very good at comparing files and directories and provides tools to manage differences.  It does those jobs well, but doesn’t claim to do more than that.

License

Assurance is released under the Apache License 2.0.

Prerequisites

The following tools need to be installed to build Assurance:

The Maven configuration will download and install the appropriate versions of the following tools:

  • Spring Framework
  • Hibernate
  • JUnit
  • H2
  • Apache Commons
  • Apple Java Extensions
  • SLF4J
  • Log4J

The following dependencies are required to run binary distributions of Assurance on Windows machines:

Mac distributions of Assurance package the appropriate JRE with the application bundle, eliminating the need to separately install Java on a Mac to run the application.  Windows distributions require that the JRE be installed prior to starting the application.

Building and Packaging

Assurance uses Maven as its primary build and dependency management system.

To build the application:

Mac

cd project_root/assurance
mvn clean package -Pdevelopment

Windows

cd project_root\assurance
mvn clean package -Pdevelopment-windows

To run the unit tests:

Mac

cd project_root/assurance
mvn clean test -Pdevelopment

Windows

cd project_root\assurance
mvn clean test -Pdevelopment-windows

To package the application for internal release:

Mac

cd project_root/assurance
mvn clean package -Pintrelease

Windows

cd project_root\assurance
mvn clean package -Pintrelease-windows

To package the application for release:

Mac

cd project_root/assurance
mvn clean package -Prelease

Windows

cd project_root\assurance
mvn clean package -Prelease-windows

IDE

Assurance was developed using Spring Tool Suite 3.6.1. Project files for the IDE are included with the distribution.

Acknowledgments

Assurance includes a modified version of the

com.ibatis.common.jdbc.ScriptRunner

class from the iBATIS Apache project.

Why a Digital Generalists Product?

Digital Generalists serves as the primary way I deliver products to the world. For full products, I want Digital Generalists to hold the copyright and serve as the primary entity releasing the software to the world.

The fact that Digital Generalists, rather than me personally, is the entity releasing the product, doesn’t affect or impact how you can use the software.  As long as you abide the attached software license, you can use the product and source as you wish.

Migrating Outlook Messages from One Install to Another by Hand without an Archive

My computer recently crashed at work, which always makes for a very bad day.  Thankfully, I had backups of everything I needed.  Getting back on my feet should have been a matter of simply restoring everything once I had a new machine in-hand.

Everything went smoothly when restoring the backups to the new machine except restoring my local Outlook data.  I was running Office 2011 and hadn’t created an archive.  I assumed restoring the old data would just be a matter of setting the active identity of Outlook to the backup of the old computer’s Outlook identity using the Microsoft Database Utility.  However, the tool kept error-ing, saying the old identity was corrupt.

From what I could tell, my company’s IT department had installed a newer patch version of Office 2011 than the one I had on the old machine and the identity structure was no longer completely compatible.  It was also possible that my previous Office identity was indeed corrupt.  Either way, I thought I had completely lost all of my saved email.

However, I was able to pull the old email backup into the new Outlook identity by hand.  Here’s how I did it.

Disclaimer:  The following steps are not for the faint of heart. You could completely break your Office installation and/or lose data if you aren’t careful or don’t understand what you are doing. I take no responsibility if this doesn’t work well for you. Proceed with caution.

All I needed to do was:

  1. Create a new identity (happens automatically when you first start Outlook).
  2. Find the new identity’s directory under the Microsoft User Data directory in the Documents folder.
  3. Find the old identity’s directory under the Microsoft User Data directory in the backup directory.
  4. Make a new backup of the new identity’s directory just in case something goes sideways.
  5. Copy all of the email-related directories from the old identity’s directory to the new identity’s directory, replacing the existing versions of those directories.
  6. Open Outlook and verify that all of the old email messages are there.

I had to iterate on this process a few times, restoring from the new identity backup and excluding directories that appeared to cause Outlook to crash from those I copied to the new identity, until the email backup loaded in Outlook.  In my situation, the directories related to email attachments were causing Outlook to crash, so I had to settle with not copying those directories over and live with the fact that old attachments were lost.

This is not an ideal solution and a pretty brute-force approach for recovering data, but it got 90% of what I needed accomplished in less than 30 minutes.  That is certainly better than the alternative of losing all of my email simply because I didn’t export an archive.

Blueprints

Evaluating a Proposed Application Architecture

At work, I’ve recently had a few conversations about the best way to evaluate candidate architectures for a software project, so I decided to put down a few ideas I have on the topic.

Project Intake

Firstly, there are several questions that need to be answered and understood by all stakeholders of a project before you can properly evaluate an architecture:

  • What are you planning to build?
  • Why are you building it?
  • Who are you building it for (i.e. who is your audience)?
  • How will success be measured?

At a technical level, most projects start with an answer to the first question and have a weak or vague understanding of the other three. However, if you can’t answer those three questions, you don’t have a good justification for the answer to the first one.

The first task is to get agreement on the answers to Questions 2 through 4 and verify the answer to Question 1 still fits. If it doesn’t, use the opportunity to identify what can be built that fits the needs of the answers to Questions 2, 3, and 4.

Business Environment Analysis

Most technical ecosystems have processes and expected technical standards that apply to all applications within the ecosystem. Your organization does things a certain way.  Your team likely has expertise in a specific technology.  Your business also likely has requirements around protecting the environment and facilitating support of the application.  These factors should be identified:

  • How are applications expected to authenticate and authorize users?
  • Are there standards around data security?
  • Are there standards around data retention?
  • Are there standards around transport protocols?
  • Are there expectations around supported platforms?
  • Are there standards around accessibility?
  • Are there standards around logging?
  • Are there standards around analytics?
  • Are there expectations or standards around interoperability across applications?
  • Are there standards regarding UI conventions?
  • Will the new product provide technical challenges to existing distribution and delivery models?
  • Will the new product provide technical challenges to existing support mechanisms?
  • Are there standards around code documentation?
  • Will the new product provide technical challenges to existing documentation procedures?

The answers to these questions will identify many of the inherent technical requirements of the system. These aspects are related to the notion of certifying the application as “good and complete” as your organization defines that term, even if informally.  If there is no formal certification process, either within your company or externally, for the application, answering these questions will help define what “good and complete” means to your product.

Technical Environment Analysis

The next step is to identify what you already have in place and how the new product will fit into the overall ecosystem.  Few applications are 100% greenfield with zero dependency on existing systems, so it is paramount to understand what environment you will be working with.

  • What systems are already in place?
  • What role will those existing systems play in the new product?
  • How will the new system affect seemingly unrelated products?
  • What types of access privileges are required to interact with these systems?
  • What integration facilities already exist in the identified systems?
  • What data does the new application need and where can it pull that data from?
  • In what formats are the data accessible?
  • What second-level dependencies exist?

Technical Architecture Review

At this point, we should have enough information to apply a proper architecture review. Firstly, you verify the proposed architecture addresses all of the concerns identified in the Business and Technical Environment analyses.

After those business-related concerns are addressed, most of the remaining aspects of the architecture will be technically focused.  However, technical concerns tend to be highly domain and context specific.  The meaning of “good and complete” when it comes to these technical concerns will be influenced by the programming language, platform, organization, and product. In general though, the following concerns tend to apply regardless of context and can be used as a base set of technical concerns to review regardless of project:

  • Separation of Concerns: Each component of the system should only do one thing and do it well. In practice, this minimally means ensuring a strong separation between the business logic implementation and the UI.
  • Abstract Interfaces: Are the touch points between the system integration points and product components done in a way that effectively hides implementation details of both sides of the integration?
  • Scalability: Can the proposed implementation easily scale to accommodate concurrent execution of the same logic processes across different data sets?
  • Maintainability: Is the architecture well reasoned, consistent, and easily modified?

When Should Architecture Reviews Occur?

You do not want an architectural review to impede the development process. Your goal is not to create the “perfect” architecture.  Your goal is to build a solid product.  However, you want to identify issues with a proposed architecture early enough to do something about any problems an architecture may have.

  • Ideally, a review of a proposed product architecture should occur before any coding has begun. (This is nearly impossible to achieve in my experience.)
  • A more realistic ideal is that a full architecture review should be conducted as soon as a potential product’s prototype or alpha implementation is minimally functional.
  • At a minimum, a full architecture review must be conducted as soon as a proposed product reaches the release candidate stage if one has not been completed earlier.
  • A full review should be conducted once prior to the product’s initial release. As soon as this occurs, summary reviews of the architecture will likely be sufficient at subsequent steps of development and maintenance.
  • For ongoing development, a summary architecture review should occur at the start of each new release and again as part of the project’s release criteria (ideally at the end of the last development sprint) or as soon as the first release candidate is identified.

A Reality of New Product Development

Most new products/applications start out as skunkworks projects. Typically an individual or a small group builds a product prototype and uses that prototype to gain approval/funding for the project.  As a consequence,  a new product often starts life with a sizable, un-vetted code base and significant technical debt. The process for bringing these products to production involves:

  • Conducting a full architecture review.
  • Documenting gaps in all of the aspects identified above.
  • Conducting a full code review.
  • Identifying all technical debt as issues/defects in your project tracking system.
  • Prioritizing architectural gaps and identifying gating issues.
  • Creating a plan to address all non-gating issues in a timely manner.
  • Verifying that all gating issues are addressed before the product is released to production.

The process I’ve laid out is intentionally light on specific procedural details because each organization is different and each technology stack and platform carry specific technical concerns.  The mechanics of a formal architecture review process need to be crafted based on the specific needs of your organization and the technology you are using.

However, this outline should provide a good abstract notion of what goes into an architecture review.  The items and concerns I’ve outlined probably aren’t comprehensive.  If you feel I’ve overlooked something important, please mention it in the comments.

Spiral by Digital Generalists Application Icon

An App of My Own

After releasing several mobile applications for the companies I’ve worked for over the last couple of years, I finally released an iPhone application of my own to the App Store, Spiral by Digital Generalists. See the launch post on my company’s website for all of the details about the app.

Spiral by Digital Generalists

Spiral is the perfect application for lovers of pocket-sized paper notepads who want to take quick notes, draw, sketch, doodle, and more! All these things can be done by simply “drawing” on the application with your finger or a stylus.

Spiral uses a world-class drawing engine that provides smooth lines and a fluid writing experience. We worked very hard to make using Spiral feel like writing on an actual notepad, and we’re proud of what we built.

Designed specifically for the smaller size of the iPhone, Spiral gives the power and features of notepad applications available only on the iPad in a way that works well on a smaller screen.

Give Spiral a try today!

SlingBox SOLO

How to Fix the SlingBox Player on Chrome When It Asks to Install Over and Over

I love my SlingBox.  It is one of the most heavily-used components in my house.  In general, the device has always worked extremely well and been headache-free for years.

However, a few weeks ago, a new update for the Chrome SlingBox player (version 2.4) was released and was a required update to continue accessing the SlingBox via Chrome.  However, when I tried to install the update on a Windows 7 machine, it would appear to install without error and ask me to agree to the license agreement.  But when I clicked “Agree”, it would simply start the process over…reinstall the plugin and ask to agree.

I tried the usual tech support tricks of clearing the browser cache, restarting the browser, and rebooting the machine.  None of them worked.

After a little digging in Chrome’s settings, I realized that a very old version of the SlingPlayer for Web extension was still installed (version 1.5 in my case).  I deleted the old extension and reopened the new version of the player.  The new version of the player now worked without a hitch.

My guess is the new version of the player has trouble unloading the old extension when it installs and the two don’t play nicely together if they’re both running in the same browser.  It would be nice if the new version of the player at least presented a dialog saying an old version of the player is installed and must be deleted manually during install rather than failing silently, but that’s water under the bridge at this point.

Regardless, the problem is easy to solve once you know what’s going on.

To delete the old version of the extension:

  1. Click the “Three Bars” button to the right of the address bar.
  2. Click Settings from the menu.
  3. Click Extensions in the column on the left.
  4. Find SlingPlayer for Web in the list of extensions that are shown.
  5. Verify that it’s a version older than 2.4.
  6. Click on the trash can button to the right of the SlingPlayer for Web name to delete the extension.
  7. Re-install version 2.4 of Chrome SlingPlayer.

That should be all that’s needed to get your SlingBox happily working with Chrome again.  If you’d like a second opinion about what to do, here’s a link to the SlingBox support site that describes roughly the same process I described above.

Markers

Marker Interfaces

Marker interfaces tend to be one of those things that your don’t think about often.  But when you have a problem they can help you solve, you think they are awesome.  The trick is knowing when they should and should not be used.

What is a Marker Interface?

Marker interfaces are basically an interface contract with no methods or properties specified.  The notion of interface contracts are common in many languages but take on many different names.  If you’re familiar with Java interfaces, Objective-C protocols, C++ pure abstract classes, or any similar technique in your language of choice, you know what I’m referring to.

Typically, an interface contract specifies a set of methods that must be implemented by any object that intends to support the contract.  This enables you to refer to an object by the contract (which typically corresponds to a functional role or feature role in the program) rather than the concrete type of the object itself.  This both clarifies how code consuming an object intends to use the object and makes it possible to easily use different concrete classes that also implement the contract without needing to change the consuming code.  The consumer doesn’t care about the concrete object type as long as it satisfies the contract.

So why on Earth would you ever want to create a contract that doesn’t specify any methods?  Most of the time, you don’t. But if you need a way to abstractly specify an object type, especially when the abstract type may have concrete instances that don’t share a meaningful inheritance chain, then marker interfaces are likely a perfect solution.  You most often have a need to specify an abstract object type like this when you have orchestration or coordination code that is transferring objects from one part of a program to another.  The orchestration code doesn’t need to use or modify the object, it just needs to move it from one place to another.

Such orchestration code tends to be both fairly abstract and highly leveraged within an application’s architecture, so you often don’t want to specify concrete types for the objects being sent back and forth.  A simple way of generically passing objects is to specify the parameters of methods in the orchestration code as generic objects.  But specifying transfer method parameters as a generic object has a few downsides.  Firstly, it doesn’t provide any guidance to the caller about what should be passed.  Secondly, literally anything can be passed.  If you accidentally pass an object you didn’t intend to, the compiler/parser won’t catch the error.

void transfer(Object data)

Marker interfaces help avoid these problems.

By using a marker interface, you can specify the intent of what should be provided to the method without restricting you to a specific type or inheritance chain.

void transfer(IFooDataObject data)

This method signature is much clearer to the person using the method what type (in the functional intent sense of the word) of object should be passed to the method.  Any concrete type can still be passed, but you have to make a conscious choice about which objects should be allowed to be passed by adding the marker interface to the type definition of the object before you can pass an object of that type. In a mature architecture, prior decisions about which objects carry this declaration can greatly minimize confusion about what to send where.

You also get a level of type checking via the compiler, so if you accidentally pass a reference to a UI control object instead of the data property on the control you intended to pass, the compiler can let you know.  Without the marker, it wouldn’t.

This technique of using marker interfaces for high-level type specification is really the one application of marker interfaces I use frequently.  I tend to not like using marker interfaces to direct flow of control within an application (i.e. “if foo implements bar then do x”) because I think such control flow is typically better governed by object state than by type. But that thought is probably worth a post of it’s own.

Four Star App Review

To Aspire to 4 Stars Rather than 5

A happy side effect of app stores and the web in general is that feedback ratings on a product are no longer difficult to find. There was a time not long ago when a consumer would need to turn to a respected source, such as Consumer Reports, to get a general consensus of quality for all but the most ubiquitous and popular products. Such a world, where information is funneled through a few curators, is one ripe for “reputation management.”

In theory, to optimize the perceived quality of your brand, all you would need to do as a company providing a product or service was:

  • build to the desires of the known entities who will be doing the evaluating
  • or figure out how to skirt the evaluation process while still presenting an air of broad market approval
  • or establish a relationship with the people doing the evaluating to ensure friendly terms
  • or even more unsavory behavior

But in a world where every potential customer is also a potential reviewer of your product/service, such brand management tactics lose some of their efficacy. To be sure, a fair amount of the behaviors mentioned above still happen, but they are not as universally effective as in days past.

One of the new realities we as product creators are faced with is that universal cultural approval, at least as we came to understand it over the last 50-odd years, is something largely unattainable. Nothing ever truly had this type of universal appeal, but the difference is that now every critic has, at least potentially, as loud of a voice in the conversation as the traditional curators do.

This is a good thing. Focus-grouped products engineered for mass appeal, be they music, literature, software, movies, or television, are, generally speaking, lowest-common-denominator creations…things without soul, passion, or inspiration because they are so deliberately engineered to speak to so many people. They are built to appeal to everyone in a shallow way and are done so to such a degree that they ultimately speak to no individual in a meaningful way at all. That intimacy has literally been factored out of their very being.

But one odd effect of this mass availability of opinion is that such a world can be crippling for those product creators starting out and looking to become established. “What if we get a bad review early? What if someone hates it?” The old answer was to quietly address the complaints of the people who hate it through largely private communication. The new answer is a little more nuanced.

You still have to address the complaints, but now we do so much more publicly.  This requires a thicker skin than in years past. Part of serving our customers now involves owning up to our mistakes or misjudgments in the open.  The process of managing the perceived quality of your brand has shifted from crafting a potentially artificial image of “everything is great all of the time” to one of concentrating on the good while acknowledging the slip ups and working diligently to ensure the good far outweighs the missteps.  “Yes, a few people hate it. Let’s concentrate on keeping it just a few people.”

Acknowledging missteps can be a very stressful thing, especially for those striving to establish themselves.  A single negative opinion can feel like the end of the world when you’re fighting so hard just to get attention.  It’s hard not imagine all of the potentially negative things that could result from a bad review.  But you can’t let yourself get trapped focusing on the “what-if”s that may or may not come about because of something you truly cannot prevent.

If you receive a bad review, you got a bad review, and you have to deal with it. Pay attention to it. Listen to what the customer is saying. If they are asking for something reasonable, something completely within your vision for the product, then there is no reason not to give them what they want, especially if it’s easy to do.  Start a conversation with the customer and come up with a plan for addressing the things they don’t like.  Attentively responding to customer feedback is surprisingly effective at fending off the scary consequences of a poor review.

But this doesn’t mean that you should blindly defer to the opinions and desires of every person who comments on what you are doing.  If you built a Volkswagen and a customer is complaining that it’s not a Cadillac, that’s not necessarily an indicator that there is something wrong with your product. They may just be trying to get a Cadillac below cost. The same rule applies doubly if you built a boat and someone complains that it’s not an airplane.  In these cases, the problem you should address is likely not your product itself but how you are positioning it within the market.

You cannot please everyone. You just can’t. If you came of age in the time when all opinions you heard in media mattered, then this feels very wrong. And you’ll want to fix every complaint from people you don’t know right away and completely. But you’ll also be lapped productivity-wise by those who’s attitude largely boils down to: “Yeah, there’s one guy in Idaho who hates what we’re doing. Thank goodness that almost all of our other customers love what we’re doing.”

In today’s world, a perfect 5 star rating is nearly impossible at any scale that would represent success. You have to be okay with a few people who don’t like how you built your product. Know in advance someone will be a real jerk about your creation. Concentrate on building something that will average a better than four-star rating, factoring in the cranks who will positively hate how you designed your product no matter what you create, especially those who don’t understand what you built.

If you do an exceptional job, you may even average 4.9 stars and become a legitimate hit. Even if you don’t, you’ll likely build something you, as the creator, have greater faith in. And that matters much more than the opinion of that one guy in Idaho.

Person with bullhorn yelling at a surprised person

Let’s Talk about Something Provocative

There’s a trend in the technology industry that I wish I saw less than I do. In many blog posts, programming books, tweet storms, etc., you’ll frequently see arguments along the lines of “I admire people who are X,” where X is a commonly-acknowledged negative trait. The author then goes on to argue how the apparent flaw is actually a virtue.

I understand the appeal in making statements like this. It makes for great copy. Counterintuitive arguments are just naturally more interesting than stating obvious truths.

Plus, there’s the added benefit that the author gains “rebel” credibility points. There’s no better way to establish yourself as an independent, “outside the box” individual than to say something that sounds so wrong that it borders on provocative and then defend the position.

One thing I don’t like about the tactic is that it often feels like a cheap way to get attention. When it’s overused, it becomes as cliche as the phrase “outside the box.” Usually, I don’t mind the tactic when the argument is compelling; in spite of the fact that when the argument is compelling, it can often be made just as effectively without the flamboyant showmanship.

What really bothers me is that frequently the author bends the definition of the negative term to the point of breaking. In Code Complete, Steve McConnell argues that laziness is something programmers should aspire to (second edition, page 830). Lazy people want to avoid doing unnecessary work, so lazy people will build tools that do repetitive tasks, and therefore lazy people will complete tasks more efficiently.

I’ve worked with my fair share of lazy programmers. Lazy programmers will never, ever build a tool. Ever. Building a tool requires thinking about the problem, doing work that wasn’t asked for, and then verifying that the tool works. Lazy programmers will copy several thousand lines of code on both sides of a conditional because they can’t be bothered to think about the problem. They will not write a tool to make the work easier.  Never.

The desire to do work more efficiently is the virtue, not laziness. People who want to work efficiently may be trying to make the job easier, but to call that laziness is simply describing the impulse to work smarter as laziness for the sake of being clever.

However, the thing that bugs me most about this technique is how easily these sound bites can be abused. One of Paul Graham’s more notable quotes is:

When I see patterns in my programs, I consider it a sign of trouble.” – Paul Graham

Doesn’t that sound smart? Isn’t that such an interesting idea? Sure it is. But it’s also part of a very large essay that was written in 2002. At the time that essay was written, the world was full of “Capital E” enterprise development advocates who tended to overzealously sell one-size-fits-all approaches to building software. People who argued that something as simple as “Hello World” should leverage a Singleton, a Factory, and a couple of Commands. When cast against that world view, Paul’s statement takes on a more nuanced relevance.

But that doesn’t diminish the huge value design patterns provide to software developers. They provide a vocabulary for describing time-tested, well-understood solutions to common problems. In an industry as young as software development, a tool like that is invaluable.

But on its own, Paul’s quote reduces the notion of their value to smart-alec one liners. Taken out of context, the quote leaves no room for discussion, they clearly must be bad. I’ve heard Paul’s quote used by a colleague to argue that anything described as a pattern must be overly complex and unnecessary.

Because of these reasons, I hope the trend of using smart-sounding, provocative statements to get attention runs out of steam soon. Or maybe I’m just too lazy to keep arguing the point.

Clearing a UIWebView’s Browser Cache

While writing a hybrid native/web application for iOS, I encountered a problem I never even bothered to consider before starting:

How do I clear the browser cache for the application?

Clearing cached HTML resources, scripts, and stylesheets is the type of browser-provided functionality that is easy to take for granted. However, when writing an application with a hosted UIWebView, you’re suddenly solely responsible for handling little issues like this.

Thankfully, programmatically clearing the browser cache for an iOS application is simple:

[[NSURLCache sharedURLCache] removeAllCachedResponses];

If your also interested in clearing out cookies, then also include this:

NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
[storage deleteCookie:cookie];
}

When and where to invoke this functionality is really up to the particular circumstances of your application.

While clearing the browser cache is the right approach for certain problems, it’s not the answer to every cache-related problem.  If you’re interested in bypassing the caching of web resources all together, be sure to look into NSURLRequest‘s NSURLRequestCachePolicy rather than aggressively clearing the application’s cache.