iDevBlogADay

Deliberate Practice: The Key To Improving

Filed in iDevBlogADay, iOS Development | Comments (0) |

A Software Craftsman’s Journey

Practice5I am better at the craft of software than I once was.

But, I am not as good a craftsman as I want to be.

The road from where I was, to where I am, to where I want to be has crossed small creeks, gentle valleys, and deep ravines. Some of the bridges were built by someone else, and I had little idea how they were made. I built some temporary, swinging rope bridges that were crossed only at great need. And, I have built some bridges and tunnels that will last a lifetime.

The risky crossings were designed in haste and sloppily constructed, often with weak materials.

The structures that last were designed carefully and built deliberately.

Preparing For Technical Challenges

Even when you have been diligent in your preparations, obstacles can appear that require your immediate attention and need a temporary solution or some outside help. But there are many challenges that can be anticipated — ones that you can prepare for.

How do you prepare yourself for coming technical challenges, do you:

  • Avoid the problem entirely by sticking to the techniques and tools you already know? “All I have is a hammer, so everything gets treated like a nail.”
  • Wait until the challenge is upon you and feverishly dig through the software component flea markets of the internet looking for anything that is “good enough”?
  • Give up and find a new line of work?
  • Spend time building your skills and adding to your developer toolbox?

If you want to grow as a developer and software craftsman, it will take effort. The best way to spend that effort is on “deliberate practice”.

Deliberate Practice

Practice1Have you ever seen a music teacher who can take someone with nothing but potential and help turn them into an outstanding musician? Have you ever had a coach who took a collection of moderately skilled individuals and built a team that performed above the level any of the individuals thought possible? Have you worked with a tutor who opened your eyes to what you were truly capable of doing?

Teachers and coaches who produce exceptional results probably have many things in common, but one in particular is the focus on deliberate practice. No effective little league baseball coach simply throws balls, gloves, and bats out on the field and tells his 10 year olds to “go practice”? It takes practice with a plan.

Practice3The same thing applies to developing software skills. You will get far better results if you take a deliberate, mindful approach to learning new skills. And just as any good teacher or coach continues to emphasize the fundamentals while building ever more complex skills, it is helpful to revisit and practice older skills in a methodical manner.

The purpose of this kind of practice is to engrain good habits and techniques so deeply that they become second-nature. This kind of ability only comes about through repeated, correct use of the techniques — facilitated by a mindful approach to skill development as free of distraction as possible.

Deliberate practice in software development means:

  • I have a specific skill in mind that I want to learn or improve,
  • I have a quality source of knowledge or instruction about that skill (classes, books, tutorials, etc.)
  • I seek good advice on how to approach the topic,
  • I have a designated time to work primarily on that skill,
  • I track my activity in some fashion so I can measure and review my progress,
  • I periodically get an objective assessment from someone who knows the subject,
  • I review my progress and adjust my plan accordingly.

Several Approaches

Practice4One example of deliberate practice is “software koans”, described in this article by Mario Aquino.

The most complete example I know of is the Ruby Koans project developed by Jim Weirich and Joe O’Brien.

There is also a fairly new project on github, Objective-C Koans, that looks promising as well.

Other good approaches include things like:

  • “Coder nights” where a group of developers get together to work on a particular task together,
  • On-line tutorials where you actually write the code yourself, and repeat the process multiple times to train your brain properly,
  • “Game Jams” where you specifically try out a new technique in the company of and help from those experienced in whatever technique you are learning,
  • Day or weekend long training sessions focused on a particular topic.

Whatever you do, I encourage you to take control of your development skills. Become the software craftsman you want to be.


This is post 3 of 10 on my second iDevBlogADay run.

We all need the support of others to do our best work. Find other like-minded developers that will provide encouragement and motivation through local user groups, conferences or meetups. A great collection of indie iOS developers have helped me stay on track through meetups, 360iDev, twitter, and iDevBlogADay.

I regularly attend Cocoa/iPhone developer meetups in Cincinnati, Ohio and Columbus, Ohio. If you are in the central or southwest Ohio area, come join me at either monthly meetup:

If you depend on iOS development for your livelihood, or would like to get to that point — you really need to attend a conference dedicated to helping you get better, and I can think of no better conference for that purpose than 360iDev — you should register today!. Much of what I am able to do professionally is due to the things I learned and the people I met there.

Finally, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

Real Life iOS project using TDD Techniques

Filed in iDevBlogADay, iOS Development | Comments (0) |

iOS + TDD = Winning Combination

I just finished a short-term iOS project where I used TDD (Test Driven Development) techniques to good advantage. I know I ended up with a cleaner design and better code than I would have otherwise.

I am not a TDD expert, nor am I a TDD purist, but I wanted to share my experience and lessons learned while it was fresh. Hopefully this will encourage other developers to add more testing to their development diet. Also, while this is not a how-to post, I did include a few links at the end of this post.1

The Project

My task was to develop a simple template based, dynamic data entry module to be used in a larger project with a very near-term delivery date. The overall client requirement for the application was to download entry form templates from a server to an iPad, where their customer would fill in a form similar to existing paper forms. Once completed, the customer could submit the results.

The high level requirements for my module were:

  • Parse a simple text-based template file,
  • Produce a dynamic form with static text and labeled text fields,
  • Properly layout the form during rotation or resizing events,
  • Provide simple methods to manage the field values on the form.

Roughly, my time looked like this:

  • 10% — Up-front design and discussions with other developers
  • 20% — Testing and development of the parser
  • 15% — Testing and development of the form builder
  • 30% — Testing and development of the layout engine
  • 15% — Building a demo app to show how the module works on a device
  • 10% — Testing and implementing modifications

Because of the tight deadline, we designed a simple format for the template that allowed for headings, subheadings, and paragraphs of text with embedded text fields of varying lengths. Here is how things turned out.

Sample Template Text

#Customer Visit Report#

##Arrival##

The customer, [[CUSTOMER_NAME|10|Customer name]], entered [[STORE_NAME|10|Store]] 
at [[ARRIVAL_TIME|5|Time]] on [[ARRIVAL_DATE|5|Date]]
to [[VISIT_PURPOSE|10|Purpose]].

##Departure##

The customer left through the [[EXIT_LOCATION|5|Exit]]
at approximately [[DEPARTURE_TIME|5|Time]].

Demo App Editor

RealLifeTDD 1

Demo App Form

RealLifeTDD 6

The field values for the template can be set before or during an edit session, and it can be told to generate a dictionary of field names and values at any point in the process as well.

The Process

At it’s core, the TDD process is:

  1. Decide what behavior to implement next,
  2. Write a failing unit test that exercises that behavior,
  3. Write the smallest amount of code it takes to make the test pass,
  4. Refactor the system as needed,
  5. Repeat.

At each step during this process, the entire suite of tests is run often to make sure no existing behavior is inadvertently broken.

My simplistic understanding of pure TDD was you should write unit tests even before the class or method that will implement the behavior exists. However, my development toolset of Xcode, GHUnit, and OCMock made that scenario pretty awkward, which slowed me down. I needed something with a better flow, so in my process, I:

  1. Decided what behavior to implement next,
  2. Added a appropriate unit test by:
    • Writing a failing unit test that exercised that behavior,
    • When necessary, creating a minimal class or adding an empty method so the target under test would build,
    • Ensuring the test target based on GHUnit/OCMock would build,
    • Ensuring the tests ran to completion in the simulator,
    • Ensuring the older tests still passed,
    • Ensuring the new test failed.

    If any of that did not happen, I made changes to the tests or module until it did.

  3. Wrote the smallest amount of code it took to make the new test pass,
  4. Refactored the system as needed by:
    • Extracting duplicate code in the tests or module into common methods,
    • Removing extraneous parameters or methods,
    • Simplifying the design as new insight is gained,

    During which I ran the entire test suite often to make sure nothing was inadvertently broken.

  5. Occasionally ran the demo app to check the visual behavior,
  6. Repeated until finished.

I am now accustomed to this style in Xcode, so each iteration went very quickly.

Limitations of Current Toolset

I did not find any limitations that would make me second-guess my decision to build this module using TDD, but there were some minor hassles.

I really like OCMock’s implementation of mock objects for Objective-C, but I had to make small changes to some module code to be able to use it. For instance, in one set of methods I would have preferred to use a primitive variable for the argument, but I needed to use a NSNumber instead because of the nature of the test I wanted to write. Even so, there were many more cases where primitive method arguments worked just fine in my tests, so it really was just a minor annoyance.

It is pretty straightforward to run a single test in GHUnit, but once I started adding more and more tests, it would have been nice to have a quicker way to do that. This project was fairly small, but I can envision some issues with a larger project. My core library ended up with 9 class files, and the test target had 9 class files with 47 unique tests. I definitely would want better ways to run individual tests and subsets of tests as the number of tests grows. At some point in the future, I would like to modify GHUnit to make this easier.

GHUnit does a decent job of sorting out the log output for each test so you can find the root cause of failures, but I find the standard Xcode/NSLog output too cluttered. It is important to form the habit of running tests very frequently, so anything that speeds up each loop is a good thing. A combination of easier control of which tests I want to run and finer control of the log output would smooth out the whole process.

While not a limitation of TDD or testing tools in particular, I wish the refactoring in Xcode 4 was better. I am convinced that if Xcode had better automated support for common refactorings such as extract method it could have reduced my development time by 5-10%. I know some Objective-C developers may not like Java, but the refactoring support in JetBrain’s IntelliJ is world-class. I have high hopes for their AppCode tool.2 Perhaps it will be popular enough to have an influence on future Xcode versions.

Lessons Learned

I really enjoyed using these techniques and I plan on following this pattern as much as possible in future iOS projects.

What I learned:

  • Testing non interface elements was a no-brainer, doing that is the minimum I should do for every project.
  • Testing the methods that arranged view layouts worked better than I expected.
  • GHUnit fits my development and testing style better than OCUnit.
  • Using OCMock to manage mock objects made writing tests easier, so it greatly increased the number of tests I was able and willing to write.
  • I want to modify GHUnit to support better organization and management of individual tests.
  • I need to spend more time with OCMock to discover if my workaround was really necessary.
  • I need to investigate Xcode logging techniques.
  • I need to give the latest version of JetBrains AppCode a serious try.

If you are not already doing so, I highly recommend adding automated testing to your development process. I also encourage you to investigate TDD to see if some of it’s techniques can help you build better code more reliably.

Have a great day!


This is post 2 of 10 on my second iDevBlogADay run.

We all need the support of others to do our best work. Find other like-minded developers that will provide encouragement and motivation through local user groups, conferences or meetups. A great collection of indie iOS developers have helped me stay on track through meetups, 360iDev, twitter, and iDevBlogADay.

I regularly attend Cocoa/iPhone developer meetups in Cincinnati, Ohio and Columbus, Ohio. If you are in the central or southwest Ohio area, come join me at either monthly meetup:

If you depend on iOS development for your livelihood, or would like to get to that point — you really need to attend a conference dedicated to helping you get better, and I can think of no better conference for that purpose than 360iDev — you should register today!. Much of what I am able to do professionally is due to the things I learned and the people I met there.

Finally, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!



1. GHUnit, Xcode, and TDD links

  • I wrote a blog post on setting up Xcode 3 to use GHUnit and OCMock,
  • I am working on a series of tutorials on TDD and iOS using Xcode 4 for Ray Wenderlich’s tutorial site, http://www.raywenderlich.com, the first of which should be available very soon,
  • I am making a presentation on OCMock at 360iDev in Denver in September.

2. JetBrains AppCode — an alternative to Xcode.

Are You Being Energized or Drained?

Filed in iDevBlogADay, Miscellaneous | Comments (0) |

Things That Energize Me

Eric

EricYesterday I was in the basement talking with one of my sons. I heard laughter upstairs and went to see what was up — at the top of the stairs I found my grandson quickly crawling towards me. He had heard my voice and decided being with grandpa sounded like a pretty cool thing, and took off like a shot to come find me.

How great is that!

Often when he is around, a short work break turns into an extended session crawling around on the floor until my knees hurt. When that happens, I always return to my basement lair refreshed.

Making Physical Things

It has been a little while since I have done any significant woodworking, but I do have a decent set of tools and supplies in the garage. I love starting with nothing more than a vague idea and transforming raw pieces of wood into something with my own two hands (and some power tools!).

Creating physical things that never existed before is very cool, and seeing the finished product sitting on the workbench is satisfying.

Wilderness

GlacierNPI love spending time with my family, and some of my favorite times are our trips to the mountains, woods, or canyons. Being someplace where none of my technology works frees me in a unique way. Even a short visit to the wilderness can recharge a part of my mind and soul that I didn’t even realize were hurting.

A hike in the canyons of the southwest, the great woods of the north, or one of our great National Parks in the mountains inspires me in a way nothing else can.

Helping People

When someone I have taught demonstrates by their work or life that they “got it”, that gives me a good feeling. But, when they surpass anything I taught or helped with — that is really exciting.

When someone like that excels, their success spills over and puts gas in my tank.

Writing Useful Software

As much as I like seeing something physical take shape, crafting something out of nothing but thought is a uniquely enjoyable experience. When the pieces come together and fit just like I want; when I can look at what I have written and honestly say to myself, that turned out pretty well; and when others find what I have finished to be good — I am pleased, and that pleasure provides energy for the next round.

Things That Drain Me

Breaking Commitments

One of the requirements of being a responsible adult is making commitments and keeping them. When I can see no way to keep a commitment I made because of my poor planning or lack of understanding of what I was doing — I pile up stress points like crazy. If I have to go back to someone and explain that I can see no way to keep the commitment I willingly made earlier, it is a serious emotional drain and can turn into a downward spiral if I am not careful.

Making a Mistake That Hurts Someone Else

Mistakes happen. We all know that. If I mess up on something that primarily hurts me, I kick myself for a minute then get my head on straight and figure out how to correct it and move on. I really don’t waste energy on the “if only” stuff any more. But, if my mistake causes someone else extra work or pain, I cringe and struggle with figuring out how to make amends.

Repeatedly Failing To Reach A Goal

If I set a goal, whether formal or informal, and don’t reach it — I am usually able to rationally analyze what went wrong and decide how to proceed. But, if there is a long term goal that I seem to be getting no closer to, or repeat the “set goal, fail” cycle for the same goal too many times, it gets very discouraging.

Beating Discouragement

We all could make lists like these. Some of the items will change, but the pattern is part of being human. One of the dangers of discouragement is that it starts a negative feedback loop that can ruin me emotionally if left unchecked.

To be discouraged is “to be deprived of courage or confidence : be disheartened”. When my courage or confidence is low or non-existent, it can be very hard to break out of that cycle. Here are some things I can do to break discouragement’s nasty grip.

Separate The Objective Reality From Subjective Feelings

Emotions are a vital part of being human, and it does not help if I pretend they don’t exist or that they don’t matter. Unfortunately, emotions can be misleading or just plain wrong, and often lag far behind objective reality. I need to find a way to sort out what is real.

I need to work backwards from my feelings to the reality. I do something like the “Five Whys” on my emotions to help determine the root causes. Once I have identified the root causes of my discouragement I am in a better position to address them.

For root causes that are outside my control, I have to ask myself if I can really afford to let events like that control my life so deeply. At this point, I need to force myself to change my goals or expectations. If I am unwilling to make that change, I need to realize I am facing a downward spiral with no escape.

For root causes over which I have some control, I have to ask myself which is more important: the status quo those causes represent or my goal. It may be difficult to decide, and my end decision may be a hybrid, but once again, something needs to change or nothing will be solved.

Enlist The Help Of Objective Loved Ones And Friends

If I am having trouble sorting out the truth about my discouragement, enlisting an objective loved one or friend makes a big difference. Even the geekiest, most introverted people need others, and I am no different. It can be painful to ask for this kind of help, and I need to use discretion, but it may be the only way for me to see what is true and what is false.

Choose To Do Things That Energize You

I need to find those things that energize me. I cannot expect to remove destructive emotions without finding things to take their place. When I have a choice, I need to choose activities, relationships, and projects that will be encourage me to keep trying.

I need to find ways to take incremental steps towards my goals. When I see progress on a small scale, that enables me to envision success on a grander scale.

Be Decisive

It is a myth that I can have it all. I need to make choices about what is important to me, what I want, what I should do, and what I cannot do.

One aspect of leadership that applies to all responsible adults is that decisions must be made with incomplete information. I will never have all the information I want before I have to make a decision, and if I keep waiting for it, I will end up in “analysis paralysis”.

So.

  • Make a decision.
  • Be willing to live with the consequences of that decision.
  • When necessary, make changes.

After all, that is what it means to be a grown up.


This marks the beginning of my second run on iDevBlogADay. Once again, my thanks go out to all the participants, readers, but especially to Miguel. Thanks Miguel!

We all need the support of others to do our best work. Find other like-minded developers that will provide encouragement and motivation through local user groups, conferences or meetups. A great collection of indie iOS developers have helped me stay on track through meetups, 360iDev, twitter, and iDevBlogADay.

I regularly attend Cocoa/iPhone developer meetups in Cincinnati, Ohio and Columbus, Ohio. If you are in the central or southwest Ohio area, come join me at either monthly meetup:

If you depend on iOS development for your livelihood, or would like to get to that point — you really need to attend a conference dedicated to helping you get better, and I can think of no better conference for that purpose than 360iDev — you should register today!. Much of what I am able to do professionally is due to the things I learned and the people I met there.

Finally, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

Old Year, New Year, Old Stuff, New Stuff!

Filed in iDevBlogADay, Miscellaneous | Comments Off on Old Year, New Year, Old Stuff, New Stuff! |

Old Year, Old Stuff

I have been an independent developer for over twelve years, using a variety of tools, platforms, and languages. I really love being on my own, even through the slow periods when I wondered if I would find any new projects to work!

Breaking away from corporate life might not be for everyone, but if you are thinking about it, I encourage you to keep working towards that goal. Being independent while my kids were growing allowed us to do many things as a family that I would not otherwise have been able to do. It also put me in a position to work on some very cool projects for different clients over the years.

Old Year, New Stuff

Twelve months ago, I set a goal of having close to half my work be iOS based by the end of the year. I did not quite reach that goal, but I can definitely see it happening in the near future.

I have really matured in my iOS development by hanging out with very smart and sharing people at 360iDev conferences, local user groups and meetups, and through twitter. Thanks to all who taught, wrote, or otherwise shared great stuff!

New Year, Old Stuff

I have gone through many changes in life, both personally and professionally, but very few have been abrupt ones. I still expect to continue on in some fashion with projects I have been working this past year. As some major projects from the past year wind down this year, it will be interesting to see what comes next.

New Year, New Stuff

This coming year will be one of those gradual changes as I move into more and more mobile development, both iOS and Android, over the coming months. I anticipate being very busy for the first few months of the year, and then seeing what happens.

iDevBlogADay.com

Today’s post marks four complete months for my participation in iDevBlogADay, and with the new work I will be involved with over the next few months, this seems an appropriate time to hand over my coveted Sunday slot to the next victim. I’ve really enjoyed being a part of iDevBlogADay.com — it has been the primary support technique to get me writing regularly again, and for that I am very thankful.

Participating has taught or reminded me of several things:

  • Just like software, good writing is work;
  • Writing usually takes longer than I think and rarely turns out exactly like I planned;
  • There is nothing like a deadline to motivate me to action;
  • Writing about what I am learning helps me understand it better;
  • The developer community in general, and the iOS developer community in particular is great!

Thanks Miguel!

Miguel, thanks so much for the work you put into setting up and maintaining iDevBlogADay, I appreciate it very much. For those who have read, commented on, and retweeted my posts — thank you, I hope you found some useful nuggets along the way.

I still plan on posting twice a month, though not on Sunday. You should subscribe to my blog and hold me accountable to this.

Please follow me on twitter if you are interested in what comes of all this new stuff!

Merry Christmas and Happy New Year!

Animating Multiple Virtual Pages Using a NIB-based View

Filed in iDevBlogADay, iOS Development | Comments Off on Animating Multiple Virtual Pages Using a NIB-based View |

Today’s post is a simplified version of some work I’m doing for a client.

For the client app, I need to browse a set of data using a NIB-based view, but do so by swiping left and right in the context of a parent view — a similar effect as Apple’s weather utility app. I didn’t explore how Apple actually does it, but the method I am using is pretty straightforward.

Overview

Demo2010Dec19_pic1.pngThis simple app displays a view for a single item at a time from an ordered list of simple domain objects. A UISwipeGestureRecognizer detects swipe events which are used to animate items on and off the parent view.

The previous view is off screen to the left, and the next view is off screen to the right. Both of these are preloaded so that when a swipe event is recognized, there is no delay while loading data for the item to be animated onto the parent view. The app cycles through three instances of the same NIB-based view controller as the user swipes.

For instance, given a list of 7 items, the app starts in this state:

  • The center view displays item A;
  • The view off screen to the right is preloaded with item B;
  • The view off screen to the left is preloaded with the last item, item G;

In this state, when a left swipe event is recognized, I want it to be interpreted as “move the currently displayed item (A) to the left and show me the next item (B)”. What happens is this:

  • The position of the center view is animated to the left off screen position;
  • The position of the right view is animated to the center on screen position;
  • The old center view becomes the new left view;
  • The old right view becomes the new center view;
  • Since the old left view is “pushed” farther to the left, it becomes the new right view;
  • The new right view is loaded with the appropriate data from the list.

A mirrored set of events happens on a right swipe event. (The app treats the list circularly, so there is no right or left edge of items.) The app also includes a tap recognizer which is used to update the tap count for each item to demonstrate how you can maintain state as views are cycled.

Handling Gestures

Each instance of SampleViewController has three gesture recognizers, swipe left, swipe right, and tap. Each also retains a reference to it’s currently displayed item when it is loaded.

The behavior for tapping is simple. When a tap is recognized on a view, the tap count for that view’s item is updated. Nothing needs to happen outside the current view and item.

The behavior for swiping is slightly more involved. Since a swipe is supposed to initiate animating the current view off the screen and a new view into the center, it would be messy for the current view to handle the animation. The best solution is to have the parent view handle the animation, since it already owns all the items and views necessary.

The cleanest way to accomplish this is by creating a simple protocol for delegating the behavior. SampleViewController.h includes the protocol definition, and adds an ivar for the delegate itself.

SampleViewController.h

#import <UIKit/UIKit.h>
#import "SampleData.h"

@class SampleViewController;

@protocol SampleViewControllerDelegate
- (void) handleSwipeLeftFrom:(SampleViewController *) source;
- (void) handleSwipeRightFrom:(SampleViewController *) source;
@end

@interface SampleViewController : UIViewController {
    UILabel *sampleIdLabel;
    UILabel *nameLabel;
    UILabel *tapCountLabel;
    UIImageView *imageView;

    SampleData *sampleData;

    id<SampleViewControllerDelegate> delegate;

    UISwipeGestureRecognizer *swipeLeftRecognizer;
    UISwipeGestureRecognizer *swipeRightRecognizer;
    UITapGestureRecognizer *tapRecognizer;
}

@property (nonatomic, retain) IBOutlet UILabel *sampleIdLabel;
@property (nonatomic, retain) IBOutlet UILabel *nameLabel;
@property (nonatomic, retain) IBOutlet UILabel *tapCountLabel;
@property (nonatomic, retain) IBOutlet UIImageView *imageView;
@property (nonatomic, retain) SampleData *sampleData;
@property (nonatomic, retain) id<SampleViewControllerDelegate> delegate;

- (void) loadSampleData:(SampleData *) aSampleData;

@end

and in the implementation simply forwards to the appropriate method of the delegate:

SampleViewController.m snippet

- (void)handleSwipeLeftFrom:(UISwipeGestureRecognizer *)recognizer {
    [delegate handleSwipeLeftFrom:self];
}

- (void)handleSwipeRightFrom:(UISwipeGestureRecognizer *)recognizer {
    [delegate handleSwipeRightFrom:self];
}

- (void)handleTap:(UITapGestureRecognizer *)recognizer {
    self.sampleData.tapCount += 1;
    [self updateTapCountLabel];
}

The delegate owns the three instances of SampleViewController, so is able to properly manage the animation between views:

Demo2010Dec19ViewController snippet (SampleViewControllerDelegate implementation)

- (void) handleSwipeLeftFrom:(SampleViewController *) source {
    if (source == centerSVC) {
        [UIView animateWithDuration:SLIDE_DURATION
                         animations:^{
                             centerSVC.view.frame = leftFrame;
                             rightSVC.view.frame = centerFrame;
                         }];

        // move untouched view to other side, and adjust names for next cycle
        leftSVC.view.frame = rightFrame;
        SampleViewController *tempSVC = centerSVC;
        centerSVC = rightSVC;
        rightSVC = leftSVC;
        leftSVC = tempSVC;

        // cache next sample
        currentIdx = [self checkIdx:currentIdx+1];
        int rightIdx = [self checkIdx:currentIdx+1];
        [rightSVC loadSampleData:[samples objectAtIndex:rightIdx]];
    }
}

More to be done

There is much that can easily be done to enhance this example, some of which I will be adding to my client’s app. Things like:

  • Adding a UIPageControl at bottom
  • Adding fade-in/fade-out toolbars for extra navigation (like the Kindle App)
  • Implementing momentum on swiping so fast swiping moves past multiple views

Hopefully this helps someone get over the hurdle of animating between sibling views. I know I made several simplifications to my original code while preparing the sample code for this blog.

You may download the sample project and use the code however you wish.

Merry Christmas!!

I wish all of you a very Merry Christmas.

Make sure you take time to relax with family and friends this week, but also take some time to read and consider the original Christmas story.


We all need the support of others to do our best. Find other like-minded developers that will provide encouragement and motivation through local user groups, regular conferences or meetups. This post is part of iDevBlogADay which has really helped me stay on track with my writing and my iOS projects.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

Think, Think, Think…

Filed in iDevBlogADay, Miscellaneous | Comments Off on Think, Think, Think… |

Think, Think, Think...

Think, Think, Think…

One of my favorite shows to watch with my young children was Winnie The Pooh — perhaps because I had good memories of watching the classic TV specials from when I was a child.

I loved the simple, happy nature of Pooh, but one downside of being stuffed with fluff is that it can be hard to think. Pooh occasionally worked very hard at it, with very limited results. I’m pretty sure my head isn’t stuffed with fluff, but some days my thinking doesn’t seem to get me any farther than Pooh’s did.

Lost in Thought — An Incredible, Productive Day

In developing software, my primary tool is my mind. Languages, frameworks, IDE’s, and editors all are important — but without the right mind to use them, and the right frame of mind, they are worthless.

My family can tell you that watching me work some days is incredibly boring. Much of those days is spent staring at the screen, at some scribbles on notepaper, or blankly into space. Those are often the days where I make the most progress.

My most productive days are when I’m so deep in thought that I don’t even remember to eat. I love those days. It’s like I can see the entire program as a single entity in my mind–I can turn it over and around, zoom in and out, pull one part out, graft something new in–it’s a incredible feeling. I wish they happened more often!

Holding it in your head

Paul Graham describes that feeling as “Holding a Program in One’s Head“. He writes:

They do more in their heads: they try to understand a problem space well enough that they can walk around it the way you can walk around the memory of the house you grew up in. At its best programming is the same. You hold the whole program in your head, and you can manipulate it at will.

He goes on to list ways to help load the entire program into your head. I may quibble about some items, but the point is valid. In order to get to that incredible, lost in the world of my program point more often, I need to figure out deliberate steps that move me away from Pooh-thinking and into that magical place.

From Pooh to TRON

There are a number of tactics I use to de-fluff my mind and achieve TRON-ness with my program, but none of them work every time, and each of them are subject to exceptions.

Working at a consistent level

  • I try to stay at a consistent level of abstraction as long as possible, switching costs between working on high-level designs and low-level implementation details can be high.
  • Rather than switching back and forth between competing projects throughout the day, I try very hard to spend most of the day on a single project — even if it is not the exact same task.

Managing distractions

  • Some interruptions are predictable, so preempt them and deal with them before they attack. (If you work at home, this may mean keeping up properly with your share of household duties before you begin.)
  • Have a notebook or software tool that allows you to quickly record any unrelated items demanding attention. Do not do any real thinking about it, simply record it. Once recorded, dismiss the thought and go back to work, those items are attacks on your concentration — do not give ground. (This only works if you have a reliable system for addressing those items, otherwise your mind will not let go.)
  • After you finish a session, deal with the items you recorded appropriately if necessary. That way you train yourself to trust that you really will “deal with that later”.
  • Schedule times or days where coworkers or family know you need to be left alone, in cooperation with them of course! On-going communication is key.
  • If twitter, facebook, news readers, or email keep pulling you away — just STOP IT.

Achieving Flow quickly

  • When you finish a session, or are interrupted, record what you are thinking or doing so that you don’t lose all your context. (See the excellent advice in the post “the interruptible programmer“.)
  • Use music, headphones if necessary. I listen to a lot of different kinds of music, but my “flow” music tends to fade into the background quickly and support my thinking, rather than require me to pay attention to it directly. For me, that usually means minimal or no lyrics, but everyone is different in that regard.
  • If you are actively working on code, then leave it in a mildly broken state. Put some notes directly in the source file where you left off so it won’t compile, add a failing unit test, something to draw your attention back to the point you left.

Manage your expectations

I don’t believe it is possible to be so consistent at your work, that you never suffer from Pooh-thinking days. So don’t set your expectations so high that your disappointment becomes a serious distraction all by itself.

You goal should be improvement, and perhaps even that “perfect” day — but don’t let the fluffy-head days get you down. There’s a good chance tomorrow will be a better day.


We all need the support of others to do our best. Find other like-minded developers that will provide encouragement and motivation through local user groups, regular conferences or meetups. This post is part of iDevBlogADay which has really helped me stay on track with my writing and my iOS projects.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

Open Source iOS CoverFlow Implementations

Filed in iDevBlogADay, iOS Development | Comments Off on Open Source iOS CoverFlow Implementations |

For my personal iOS development, I have a technical experiment and exploration todo list. It includes techniques I need to get better at, open source packages to investigate, that sort of thing.

I try to keep the items on the list small enough to do enough prototyping in a single evening to satisfy my curiosity. That way I am willing to move on during my next exploration session. The point is not usually proficiency, but enough familiarity to decide if the technique or framework merits further study. I often keep the code around as a reference, but it is definitely throwaway code, so it’s in a separate folder than “real” code.

One of the items on my list was to find and investigate CoverFlow clone examples floating around the intertubes. I found several that were based on Apple’s private APIs or were old enough that I was not interested. But, I did find two that I spent some time investigating.

OpenFlow, a CoverFlow clone developed during iPhoneDevCamp

The first was OpenFlow by Alex Fajkowski, released at iPhoneDevCamp in August, 2009. It is hosted on GitHub, but it does not look like it has been updated since then.

There is sample code included with the OpenFlow download, but it does not have a simple, quick-start example to get an initial feel for the package. Fortunately, others have written posts with some simple examples, two I looked at were:

A simple example by Julios Barros’ (@juliobarros).

And another simple example, but with more pictures and step-by-step details.

I liked OpenFlow well enough, but the current implementation did not allow for flicking through multiple covers. It behaves a little more like iTunes on the mac, not like browsing albums on the iPhone iPod app. Fortunately, my other “find” did have better flicking behavior, with tweakable momentum settings.

FlowCover, an easy to use OpenGL ES based CoverFlow clone

My other “find”, FlowCover by William Woody is essentially one OpenGL ES class with a simple helper class for data caching.

I like simple. Since I am likely to tweak the behavior of whatever I find, the simpler and cleaner the starting point — the better.

I added the two classes to my prototyping base project, and I was off and running. FlowCover works pretty much as expected, behaving smoothly and simply. The only change I made to FlowCover.m was to allow for different scaling when in landscape and portrait modes. Other than that, it worked just as I wanted.

Conclusion

If you are interested in adding some Cover Flow type behavior to your app, I recommend checking out both projects.

OpenFlow is based on UIKit, and has more features than FlowCover.

FlowCover is based on OpenGL ES, has few features, but behaves a little more like I expected Cover Flow on an iPhone to behave.

Either is a good choice, but my needs are simple enough right now that I think I will be using FlowCover.


As an indie developer, one of the best things you can do is to find like-minded developers that will provide encouragement and motivation while pursuing a commitment. A great collection of indie iOS developers have helped me stay on track, many of them are either developers associated with iDevBlogADay, or those I have met through the 360iDev conferences. I also encourage you to find local NSCoder nights, developer meetup groups, or other user groups to keep your motivation on track. If there aren’t any meeting locally, try to find one other developer and start one.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

Winston Churchill's Keys To Success

Filed in iDevBlogADay, Miscellaneous | Comments Off on Winston Churchill's Keys To Success |

One of the difficulties in discussing success is that each of us may have a different definition. I believe that ultimate success in life depends on my relationship with my creator1, but I also believe there are many aspects of success that all of us can agree on.

Lessons from Winston Churchill

I would not equate building an application or creating a game with the major events surrounding Winston Churchill’s life and career, but there are lessons we can apply from what he said and wrote.

On Failure

“Success is the ability to go from one failure to another with no loss of enthusiasm.”

“Success is not final, failure is not fatal: it is the courage to continue that counts.”

Learn from your failures rather than let them discourage you from continuing.

On Quitting for the Wrong Reasons

“Never give in. Never give in. Never, never, never, never–in nothing, great or small, large or petty–never give in, except to convictions of honor and good sense. Never yield to force. Never yield to the apparently overwhelming might of the enemy.

There are times to quit and there are times to persevere.

It is difficult to tell the difference, but if you think it might be time to quit, wait until you are thinking clearly and can evaluate the situation properly before making that decision.

On Criticism

“Criticism may not be agreeable, but it is necessary. It fulfills the same function as pain in the human body. It calls attention to an unhealthy state of things.”

Not every bit of criticism is valid, but I have found that most criticism contains at least a kernel of truth — find that kernel and decide if you need to make corrections.

On Mediocrity

“I am easily satisfied with the very best.”

Try very hard not to settle for mediocre results. Often it is better to cut something out completely rather than include some half-baked feature.

On Difficulties

“Mountaintops inspire leaders but valleys mature them.”

“The pessimist sees difficulty in every opportunity. The optimist sees the opportunity in every difficulty.”

Sometimes the only reason one person succeeds where others have tried and failed is simply because they pushed on through the valley to the other side when no one else did.

On Worries

“When I look back on all these worries, I remember the story of the old man who said on his deathbed that he had had a lot of trouble in his life, most of which had never happened.”

“Let our advance worrying become advance thinking and planning.”

Do not focus on things that might happen. You have enough things that are happening right now that you should handle.

Final Thoughts

Winston Churchill experienced things I never will, through times that I hope to never see.

But, his perspective and wisdom, though not perfect, can be invaluable when thinking about success. I hope you found a nugget that helps you this week.


As an indie developer, one of the best things you can do is to find like-minded developers that will provide encouragement and motivation while pursuing a commitment. A great collection of indie iOS developers have helped me stay on track, many of them are either developers associated with iDevBlogADay, or those I have met through the 360iDev conferences. I also encourage you to find local NSCoder nights, developer meetup groups, or other user groups to keep your motivation on track. If there aren’t any meeting locally, try to find one other developer and start one.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!


1. Matthew 16:25-26 “For whoever would save his life will lose it, but whoever loses his life for my sake will find it. For what will it profit a man if he gains the whole world and forfeits his soul? Or what shall a man give in return for his soul?”

Will Code For Fun

Filed in 360iDev, iDevBlogADay, iOS Development | Comments Off on Will Code For Fun |

My work is fun.

It usually is challenging and non-trivial, but it is also fun.

My clients find the results valuable, but it is still fun.

I attended 360iDev this week which was great fun — but it is not why my work is fun.

Working with smart and creative people is fun — but they are not really why my work is fun either.

My work is:

  • Long hours of head down struggles with conflicting demands and confusing requirements;
  • Opportunities and possibilities rattling around my head for days;
  • Researching problems and fixing them cleanly;
  • Struggling with multiple design iterations to find what works best;
  • Discovering what will best meet people’s needs;

I’ll be honest, not every day is fun, nor is every task, but almost every one could be. I’d like to explore what it takes to turn the drudgery into fun, and move from just slogging through tasks to actual enjoyment.

What is “Fun”, Anyway

In A Theory of Fun, Ralph Koster says:

fun is the act of mastering a problem mentally.

My work certainly has problems that can only be solved with the mind, and successful work definitely includes mastery. So, by Koster’s definition, it is possible for my work to be fun.

Jesse Schell says in The Art of Game Design that:

fun is pleasure with surprises.

Well, my work often has surprises, but they do not all bring pleasure. But, his definition seems to have enough room in it to say that my work can be fun.

I Recognize “Not Fun” When I See It

But what about work that seems *not fun* by any reasonable definition. What is it that takes those problems, mental challenges, and surprises and transforms them into fun? The process that Schell uses to define game has helped me understand what that transformation of work from “not fun” to “fun” might require.

He builds a definition for “game” by investigating what others say about fun, play, and other terms which made me think about what makes my work fun. Key among those terms is play, which he defines as “manipulation that satisfies curiosity”. The bulk of my work is manipulating things like ideas and algorithms, so this seemed like an interesting place to start.

Is It “Work vs. Play” or “Work and Play”

I manipulate things in my work, but what about satisfying curiosity? And what about fun?

Notice that Schell’s definition of play does not require it to be fun — you can play with something that turns out not to be fun. That seems to be close to work — you can work with something that turns out not to be fun. Since my desire is to make my work fun where I can, I think looking at play a little more might be helpful.

He quotes George Santayana on play:

Play is whatever is done spontaneously and for its own sake.

When I think of work, spontaneity does not leap to mind. But when I am free to choose projects and clients, there can be a spontaneous feel to it, and it definitely includes a “for its own sake” component. When I have control over what I work on, I will choose the more interesting work — work where I can learn, grow, and satisfy my curiosity about something. So the more freedom I have in choosing projects and clients, the more fun my work will be.

This leads to my first tip about making my work fun.

Tip #1 — Do not let current constraints on your work immobilize you, they should motivate you to find ways to have more control over your work.

Attitude Is King

But, there are always some tasks we must do that do not really appeal to us. Schell expands on “for its own sake” with examples and observes “an activity itself cannot be classified as a ‘work activity’ or ‘play activity’. Instead, what matters is one’s attitude about the activity”. This leads to another tip:

Tip #2 — While you cannot always choose work activities, you can always choose your attitude.

Schell combines several concepts and concisely defines a game as “a problem-solving activity, approached with a playful attitude”. I believe this applies directly to my work. Even unpleasant tasks can be made more palatable, and perhaps even fun, with the right attitude.

Adjusting My Attitude — The Key To Making Work Fun

Fresh Eyes

Two young developers I met this week at 360iDev illustrate how work can be fun. Santiago and Charlie, somewhere around 13 years old, are friends who share a love for making their iPhones do cool things. I won’t pretend to know them well enough to understand all their motives, but they were most definitely having great fun. They were right there in the front in most sessions, even participating in the 360iDev Game Jam until about 2am. It was a joy to watch them.

Watching them during the Game Jam leads to another tip:

Tip #3 –Look with wonder at the cool things that are possible.

(They both have several apps in the store. If you are interested check out Santiago’s Apps and Charlie’s Apps.)

Thankfulness

I am very blessed to be able play around with such cool and powerful stuff, which leads to the last tip:

Tip #4 — Remember to be thankful for the opportunity to attempt great things, whether or not you end up making a living from it.

My Work Is Fun, Yours Can Be Too

How fun is your work? If the answer is “not very”, remember these things:

  1. Find ways to have more control over your work,
  2. Choose your attitude towards your work,
  3. Look at your work with wonder at the possibilities,
  4. Remind yourself to be thankful that you can play with such cool stuff.

As an indie developer, one of the best things you can do is to find like-minded developers that will provide encouragement and motivation. A great collection of indie iOS developers have helped me stay on track, developers from local user groups, those associated with iDevBlogADay, or those I have met through 360iDev. I encourage you to find local NSCoder nights, developer meetup groups, or other user groups to keep your motivation on track. If there aren’t any meeting locally, try to find just one other local developer and start one.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!

My Growing iOS Developer Toolbox — Logging With Levels and Categories

Filed in iDevBlogADay, iOS Development | Comments (0) |

I really love working with iOS and Objective-C, but I still feel like I am missing some items from my developer’s toolbox. (I am using the term ‘tool’ generically to cover anything from a fairly simple development pattern to a full fledged application.) Those missing items fall into several categories:

  1. Existing features within Xcode or other Apple tools that I have not yet found;
  2. Tools that are not needed within this new environment that I only think I need;
  3. Tools that have no direct one-to-one replacement;
  4. Tools that have some third party support that I have not yet found;
  5. Useful tools that really do not exist yet in the Objective-C world.

I usually learn a new language itself much faster than I get comfortable with the new environment, development style, and available tools. So, when I feel like something is missing, I know it might just be part of the learning curve. When I move to a new platform, I want to be willing to think differently and adapt to it rather than fight it — the difficulty is often deciding which category that missing piece falls in.

A Tool Missing From My Objective-C and iOS Development Toolbox

One of the the simple tools I use heavily during development in Java is Apache Commons Logging and Log4J. For those unfamiliar with the Java world, they are simple packages that allow you to easily manage development and production logging. They support multiple categories and multiple levels within each category, and are easily configured at runtime via a simple text file. For the majority of applications, you can leave the logging in place and just disable it in the configuration file with a negligible impact on performance. It is great to be able to come back to existing code to make changes and simply enable detail level logging for individual categories (usually based on class name) to more easily monitor what is happening.

When I first started heavily into iOS and Objective-C last winter, I went searching for replacement tools in several areas, including this one. I did not find a one-to-one replacement, mostly because of the difference in the development environment, but I still had a desire for something close. My searching found several people doing limited forms of this via custom macros to wrap NSLog statements. I like to credit those on whose worked I build, but I did not track the source of most of what I learned and it has been too long for me to remember. So feel free to use what you find here however you wish, knowing that much of it did not originate with me.

Requirements for Objective-C Logging

I have no desire to implement an entire framework to support logging, nor do I want to duplicate everything from the java packages, even though there are lots of useful things I am ignoring.

My simple requirements are:

  1. Control logging horizontally via debug levels;
  2. Control logging vertically via categories;
  3. Enable or disable logging via very simple changes;

Debug levels are important to me because usually I want only higher level log messages displayed to avoid unnecessary detail in the console log across all of my classes.

Categories are important to me because when I am focused on a particular subsection of code, or an individual class, I want to be able quickly disable logging at any level for all other categories. This allows me to more quickly find the pertinent messages and finish my task, whether it is debugging or implementing a new feature.

It is also important to me to not add configuration complexity to my project (Xcode has enough of that), so I wanted to have only one or two places where I could tweak the levels and categories.

Macros for Objective-C Logging

I reuse IGDebug.h across projects, so it does not contain any project specific definitions. For convenience, I include this file in my precompiled header.

I enable debug logging for a particular target by setting the value of Preprocessor Macro to IGDEBUG_MODE=1 in its configuration for the debug Distribution. By setting this only for your Debug distributions, you can ensure none of the debug logging is included in your release distributions.

My project specific categories are defined in a separate, project specific header file. I recommend placing the category defines in a single file, it makes it easy to find them, but the IGDebug macros do not care where you define your category.

IGDebug.h

/*
 *  Created by Douglas Sjoquist.
 *  Copyright 2010.
 *  Free to use or modify for any purpose.
 */


// Define IG_DEBUG_MODE for Debug distributions in project build config files

// if IG_DEBUG_MODE is set, then these macros are in effect, otherwise they do nothing
//   IGDStatement includes enclosed text as a statement, only simple statements will work
//      (intent is to used when a temporary object needs to be created to display in subsequent log message)
//
//   IGDLog takes 3 or more parameters
//      l   --  debug level, an integer value that is compared against the value of
//              IGDBG_MAX_LOG_LEVEL to determine how detailed of log messages should be displayed
//      c   --  additional condition that must be true to display log message
//              the intent is to allow specific classes to be turned on and off via individual
//				#defines, but it can be used for any purpose whatsoever
//      s   --  NSLog format string to use
//      ...     Var args that match the format string
//
// IGALog displays similar log messages, but is unconditional (no debug level, conditions, and ignores IG_DEBUG_MODE)
//
// IGDSLog and IGASLog behave the same, except they include the self pointer as well
// IGDFLog and IGAFLog behave the same, except they include the filename/linenumber as well
// IGDSFLog and IGASFLog behave the same, except they include the self pointer and filename/linenumber as well

#define IGDBG_TRACE 3
#define IGDBG_DEBUG 2
#define IGDBG_INFO 1
#define IGDBG_WARN 0

#define IGDBG_MAX_LOG_LEVEL IGDBG_INFO

#ifdef IG_DEBUG_MODE
#define IGDStatement( s ) s
#define IGDLog( l, c, s, ... ) if (((l) <= IGDBG_MAX_LOG_LEVEL) && (c)) NSLog( @"%@", [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGDSLog( l, c, s, ... ) if (((l) <= IGDBG_MAX_LOG_LEVEL) && (c)) NSLog( @"<%p> %@", self, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGDFLog( l, c, s, ... ) if (((l) <= IGDBG_MAX_LOG_LEVEL) && (c)) NSLog( @"%@:(%d) %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGDSFLog( l, c, s, ... ) if (((l) <= IGDBG_MAX_LOG_LEVEL) && (c)) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define IGDStatement( s )
#define IGDLog( l, c, s, ... )
#define IGDSLog( l, c, s, ... )
#define IGDFLog( l, c, s, ... )
#define IGDSFLog( l, c, s, ... )
#endif

#define IGALog( s, ... ) NSLog( @"%@", [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGASLog( s, ... ) NSLog( @"<%p> %@", self, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGAFLog( s, ... ) NSLog( @"%@:(%d) %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define IGASFLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )

Using IGDebug.h

The examples shown below include IGConstants.h, a project specific file I use to configure all my logging categories in a single place. There is no magic to it, it is just a list of #define statements to define the adhoc logging categories I use.

There are two types of macros defined in IGDebug.h: logging macros intended for use in debug distributions only, and macros that should produce log output in all distributions. The debug versions are prefixed with “IGD” and the always log versions are prefixed with “IGA”. There are four different macros in each set:

  1. IG?Log — functions as a simple wrapper for NSLog, adds no extra output
  2. IG?SLog — adds the self pointer to the log output using <%p>
  3. IG?FLog — adds the file name and line number to the log output
  4. IG?SFLog — adds the self pointer, the file name, and line number to the log output

The debug versions of these macros also include two additional parameters to control the logging level and assign it to a category. The logging level parameter should be an integer, and will be compared to the IGDBG_MAX_LOG_LEVEL definition defined in IGDebug.h. The category can be any value that evaluates to true or false — in my exmaples I use simple #define values of 1 or 0 to enable or disable log output for that category.

Example usage

IGConstants.h

#define GESTURE 1
#define SUBGESTURE 1
#define TOUCHINFO 1

IGTouchInfo.m

- (IGTimeAndPosition *) addCurrentTimeAndPositionInView:(UIView *) view {
    IGTimeAndPosition *timeAndPosition = [[IGTimeAndPosition alloc] initWithTime:[NSDate timeIntervalSinceReferenceDate] position:[touch locationInView:view]];
    IGDSFLog(IGDBG_DEBUG, TOUCHINFO, @"createCTAP: %@(rc=%u)", timeAndPosition, [timeAndPosition retainCount]);
    [timeAndPositionArray addObject:timeAndPosition];
    [timeAndPosition release];
    return timeAndPosition;
}

Caveats

Because these are macros, you may find cases where values you want to display confuse the preprocessor. As a workaround, I added a IGDStatement macro that simply wraps an existing single Objective-C statement. The intent is to be able to calculate a value to use in a logging statement that is only included when IG_DEBUG_MODE is defined.

Example usage of IGDStatement

...
    CGFloat movementRange = [touchInfo movementRange];
    NSTimeInterval timeDiff = [touchInfo timeDifference];
    IGDStatement(CGPoint min = [touchInfo minimumPosition];)
    IGDStatement(CGPoint max = [touchInfo maximumPosition];)
    IGDFLog(IGDBG_DEBUG, SUBGESTURE, @"min=%f,%f max=%f,%f range=%f, time=%f", min.x, min.y, max.x, max.y, movementRange, timeDiff);
 ...

Conclusion

Feel free to use IGDebug.h as-is or however you wish in your projects. If you have improvements, I’d love to hear about them in the comments or on twitter.

I have been using a form of this in my projects since spring, and it is finally becoming a habit for me. Whatever tools you use, getting to the “I don’t have to think about this” level is important for your productivity, so choose a few and get in the habit of using them, whatever they are.


As an indie developer, one of the best things you can do is to find like-minded developers that will provide encouragement and motivation while pursuing a commitment. A great collection of indie iOS developers have helped me stay on track, most of them are either developers associated with iDevBlogADay, or those I have met through the 360iDev conferences. I am writing this from the lobby during the pre-conference day of 360iDev in Austin, and I am really look forward to the conference.

Also, here is a little more information about me, Doug Sjoquist, and how I came to my current place in life. You should follow me on twitter and subscribe to my blog. Have a great day!