Managing Relationships With App Users (CIDUG meeting, October 25, 2011)

Ran Flasterstein gave a presentation tonight about his experiences in communicating with users of his apps. He mainly spoke about the ways that he encourages conversation with his users through feedback and e-mail.

Next month at the CIDUG meeting, I will be giving my presentation, Open Source iOS Projects. Hopefully, since the meeting date is only a couple of days before Thanksgiving, there will be fewer folks there for me to inflict my wit and wisdom on.

BTW, happy birthday to the pride of Kelvington, Wendel Clark. In my humble opinion, they should not even bother giving any other Leaf the C.

Paradise lost?

A couple of years ago, I wrote a blog post about displaying and dismissing a view controller in an iPhone application. To get rid of your view controller from within that view controller, you would simply run this line of code:

[[self parentViewController] dismissModalViewControllerAnimated:YES];

Alas, with the update to iOS SDK version 5, this no longer works. And in fact, if you spelunk through the UIViewController.h file, it does say that as of 5.0, it will no longer return the presenting view controller.

Luckily, you can just do this instead:

[self dismissModalViewControllerAnimated:YES];

BTW, happy birthday to Roger Moore, star of the excellent films “The Cannonball Run” and “ffolkes”.

Just one more thing…

Love him or hate him, our industry lost a real visionary today.

Over the next days and weeks, depending on who you listen to, there will be many words used to describe Steve Jobs. Which words are true? The simple answer is that all of them will be true, and none of them will be true.

The reason for this apparent contradiction is because that he was an individual that defied convention. Sure, not all of his ideas and products were slam dunks, but who among is so perfect as to measure up to our own ideals?

Simply put, a lot of Apple’s products are flat out awesome. Oh, and by the way, did I forget to mention that Steve ideas and products brought about massive changes in the computer industry, the consumer electronics industry, the motion picture industry, and the music industry?

Yes, kind words even though Steve killed the Newton platform and caused my software development company in Florida all sorts of problems back in 1998. I just wish I had bought the stock back then when it was right around the $20 level.

Steve, you will be missed.

September 11 retrospective

The last thing the internet needs is yet another commentary about September 11, so I will be brief.

I used to listen to sports radio. A lot. Especially when I lived in Safety Harbor, Florida.

It seemed like just another Tuesday morning drive to the office down in St. Petersburg. Tony Bruno was on the air yakking about something or the other, who can remember what. I pull into the First Union parking lot at around 10 minutes until 9 or so, and Tony is making some kind of comment about a fire in a skyscraper in New York.

Cross the street, quick elevator ride up to the 6th floor, and there is dead silence amongst my team. When it was clear what was happening, my first thought was that my wife worked on the 29th floor of a building in downtown Tampa, which thankfully was evacuated very quickly.

The comic relief that morning was provided by Jim, our company president who was scheduled to fly out of town on business that morning. He called me at the office from his cell phone as he was waiting in traffic trying to get to the Tampa airport, asking me what was going on. (I am not sure what Jim listens to while driving, apparently nothing.) I told him to turn around and head back home.

Much like everyone else on that day, we followed along with the news at the office until the internet was overwhelmed with traffic, at which point we switched over to radio. I tried to keep everyone focused to try and get something done, but it was a lost cause and we closed the office a few hours early.

The air travel experience was much different when I traveled to my brother’s wedding 10 days later. My wife also had a plane ticket but would not go with me, and I could not blame her. Are we better or worse off in this country after the events that occurred on that day? I am not sure how to answer that, so I will leave it up to posterity.

But I will tell you to make sure to hug family and friends today to remind them how much they are appreciated.

We must not fear.

We must not forget.

How to make random entries into the iPhone address book

Are you a frustrated iOS developer working on an app that has to access the built-in address book on the device? Frustrated because you can’t find sample data to populate the address book in your Simulator, and you are too busy to create a bunch of test data?

Well, for a limited time* only, we at the Do Something Here Labs have a deal for you. For just a minimal** postage and handling charge, you too can use this sample code below to create random entries to your hearts content in your very own iOS app.

Here is the code in question. Simply drop this method into your Objective-C source code and call it in your app, and you will soon have contacts, contacts, and more contacts.

#import <AddressBook/AddressBook.h>
 
- (void)addressBookData
{
#define NUMBER_OF_RANDOM_ENTRIES    25
#define GENDER_OF_NAMES             @"m"    // use m for male or f for female
#define URL_FORMAT  @"http://old.wave39.com/roster/generate.php?f=csv&g=%@&num=%d&limit=99"
 
    NSString *urlString = [NSString stringWithFormat:URL_FORMAT, GENDER_OF_NAMES, NUMBER_OF_RANDOM_ENTRIES];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
    NSString *stringData = [NSString stringWithUTF8String:[data bytes]];
    NSString *areaCode = [NSString stringWithFormat:@"%03d", (arc4random() % 799 + 200)];
 
    NSArray *lineArray = [stringData componentsSeparatedByString:@"\n"];
    for (NSString *line in lineArray)
    {
        if ([line length] > 0)
        {
            NSArray *fieldArray = [line componentsSeparatedByString:@","];
            if ([fieldArray count] == 3)
            {
                ABAddressBookRef addressBook = ABAddressBookCreate(); 
                ABRecordRef person = ABPersonCreate();
                NSString *phone = [NSString stringWithFormat:@"%@-%03d-%04d", areaCode,
                                   (arc4random() % 799 + 200), (arc4random() % 9999)];   
                ABMutableMultiValueRef phoneNumberMultiValue = ABMultiValueCreateMutable(kABPersonPhoneProperty);
                CFStringRef phoneType = (arc4random() % 2 == 0 ? kABPersonPhoneMainLabel : kABPersonPhoneMobileLabel);
                ABMultiValueAddValueAndLabel(phoneNumberMultiValue, phone, phoneType, NULL);
                ABRecordSetValue(person, kABPersonFirstNameProperty, [fieldArray objectAtIndex:1], nil);
                ABRecordSetValue(person, kABPersonLastNameProperty, [fieldArray objectAtIndex:2], nil);
                ABRecordSetValue(person, kABPersonPhoneProperty, phoneNumberMultiValue, nil);
                ABAddressBookAddRecord(addressBook, person, nil);
                ABAddressBookSave(addressBook, nil);
                NSLog(@"Created record for %@ %@ (%@: %@)", [fieldArray objectAtIndex:1], 
                      [fieldArray objectAtIndex:2], phoneType, phone);
                CFRelease(phoneNumberMultiValue);
                CFRelease(person);
                CFRelease(addressBook);
            }
        }
    }
 
    NSLog(@"Done creating address book data.");
}

On a housekeeping note, make sure to include the AddressBook.framework library in your application, and make sure to import the AddressBook.h header file as shown. Although if you are already developing an app that accesses the address book, you probably have this covered.

Also, your device or computer needs to have internet access while the code is running, as the code accesses a simple PHP application that I did a while back to do random sports roster generation. (The PHP application will generate a maximum of 99 entries at a time, so if you want to try and have it generate 42 billion names with one call, go right on ahead and try.) OK, I probably should not be blocking the main thread with the synchronous request, but I did not have time do something other than the most quick and dirty solution possible.

But wait, there’s more.

Happy birthday to Terry Bradshaw. I’m sure that if Terry was developing an iOS app, and he needed to populate some random address book entries, this would be the code he would use. And if it is good enough for Terry, isn’t it good enough for everyone?

(* = For as long as this web site is accessible on the internet)

(** = $0.00)

Batter vs. Pitcher Lite now available

Maybe someone at Apple was reading my blog yesterday, because a couple of hours after I posted my lamentations over the BvP Lite approval wait, the app went into the approval process and was approved then an hour or so after that. Awesome job Apple, thanks.

Here is the link to the Batter vs. Pitcher Lite free app:

Batter vs. Pitcher Lite

No birthday, anniversary, or holiday wishes at this time, but I would like to say that I am totally impressed with my new 13″ MacBook Air. It seems to be more than adequate for building iOS apps, and due to the SSD drive, it actually seems to compile, build, and fire up the simulator much faster than my old MacBook Pro.

Still patiently waiting

Well, I took the version 1.0 BvP app and turned this 1 batter vs. 1 pitcher app into a free app, and submitted this new app to iTunes Connect. They seem to be dragging their feet on this new app, as it has been over a week. App revisions seem to go much faster, it only took a few days when I submitted the 2.0 BvP app, which features the ability to have multiple pitchers vs. multiple batters. This is a much more useful mode for fantasy baseball or for statistical research.

BTW, Happy Birthday to John Boker. (Not the John Boker who played baseball for the Ogden Raptors, but “the” John Boker who was formerly a track star and also happens to be Ohio’s pre-eminent bacon tea connoisseur.)

Two superviews are better than one

So I have a table view that is built by using a custom cell that I built in Interface Builder and load up in my view controller. This UITableViewCell has a bunch of UIButton controls right off the root of the cell view in it that I need to snag the action on, and of course there can be a lot of cells in the table. In order to do this as compactly as possible, I wanted to just create one IBAction method, and funnel all button presses to that method. Then, inside the method, I would just read the tag of the sender to decide what button was pressed, and then back up one level to get the cell, ask the table for the index path of that cell, and then I would know which row to act on.

Well of course it did not work as expected the first time. For some reason, when I asked the table for the index path of the cell, it would always return a nil index path. So here is the final code that works.

UITableViewCell *cell = (UITableViewCell *)sender.superview.superview;
NSIndexPath *path = [contactsTable indexPathForCell:cell];

As I studied the problem, I discovered that the first superview off the sender does not get you far enough back, you have to go back another superview.

BTW, thanks to Leo Fender, born this day in 1909, for founding a company with such awesome products.

I Want My MP3 (Reprise)

Well, I gave in and uninstalled the official Twitter app from the Droid Charge, and what do you know, my MP3s play. I can now enjoy my ringtone of “The Analog Kid”.

I Want My MP3

Please take a look at the two electronic devices in the following picture:

Electronic devices

One of these devices plays the MP3 files that I ripped in iTunes from CDs that I own, and one of these devices does not. (The Joe Satriani pick is included just to give you an idea of the size of the device on the left.)

I think you can see where I am going here with this one. The cheapo flimsy extra-white Kube MP3 player on the left plays the MP3 files just swimmingly. Conversely, this is not exactly what I am expecting to see when I go to the music player on my shiny new Samsung Droid Charge from Verizon:

Android screen shot

Anybody have any ideas? If I reboot the device, the MP3 files play for a while, and then it goes back to the wonderful “Sorry, the player does not support this type of audio file” message. Also, I have no intention of uninstalling the Twitter app. I use the Twitter app and I am not sure if it would even go away if I tried to uninstall it. (I have tried repeatedly to uninstall “Let’s Golf” from the device, but alas each time I uninstall it, it shows back up again.)

If you would like to follow along with this on the Verizon support board, please feel free…

MP3 files will not play

Unfortunately, you would need to sign up for a forum account to contribute. If you have something to add, please feel free to click the Comment link just below this post.

BTW, Happy Pi Approximation Day. July 22, 22 divided by 7 is 3.142857 (decimal pattern then repeats), which is as close to pi as you can get with a fraction made up of a numerator and denominator that are reasonbly small.