Archive for July 2011

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.

It’s like, how much more awesome could “Hair Nation” be?

And the answer is, none more awesome…

It's Big Bottom time!

I think this seals the deal now, I am going to have to be subscribing to satellite radio when the trial subscription runs out on my new car. Sirius/XM stockholders should be happy…

Shameless plug

As long as the Pittsburgh Pirates are playing above .500 baseball, I will be discounting the Batter vs. Pitcher app from $2.99 to $0.99, so get it while they’re hot…

Batter vs. Pitcher

BTW, Happy Bastille Day!

Logging the view hierarchy

I found some nice code on Stack Overflow for outputting the view hierarchy to the console, and I thought it was worthy of a few mention after some minor modifications of course.

The code takes in a view and iterates through the whole view hierarchy from that view, outputting the vital statistics of the views to the console. I modified the code a bit to pass in a parameter initially to control if the logging routine walks the superviews, and I also made the output show the screen coordinates in integers instead of showing floats with 4 decimal places.

Now, with a line like this in my application (don’t forget of course to import the InspectView header file):

[InspectView dumpViewToLog:self.view findParent:YES];

I can get this in the console:

2011-07-09 16:33:10.475 MyApplication[1038:207] 
Inspect view hierarchy -----------------------------------
Original view is (0x6840800)
UIWindow (0x6314b00): frame origin: (0, 0) size: (320, 480) [tag=0] UIView : UIResponder : NSObject : 
.   UIImageView (0x6314a70): frame origin: (0, 20) size: (320, 460) [tag=0] UIView : UIResponder : NSObject : 
.   UILayoutContainerView (0x63190a0): frame origin: (0, 0) size: (320, 480) [tag=0] UIView : UIResponder : NSObject : 
.   .   UINavigationTransitionView (0x631a7e0): frame origin: (0, 0) size: (320, 480) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   UIViewControllerWrapperView (0x6149dd0): frame origin: (0, 64) size: (320, 416) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   UITableView (0x6840800): frame origin: (0, 0) size: (320, 416) [tag=0] UIScrollView : UIView : UIResponder : NSObject : 
.   .   .   .   .   UITableViewCell (0x615cad0): frame origin: (0, 290) size: (320, 129) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIGroupTableViewCellBackground (0x614b9b0): frame origin: (9, 0) size: (302, 129) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UITableViewCellContentView (0x615d590): frame origin: (10, 1) size: (300, 126) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x614b2f0): frame origin: (10, 5) size: (279, 21) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6149800): frame origin: (10, 34) size: (227, 84) [tag=4] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIImageView (0x615c950): frame origin: (10, 1) size: (300, 10) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   UITableViewCell (0x6385000): frame origin: (0, 204) size: (320, 66) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIGroupTableViewCellBackground (0x615b0f0): frame origin: (9, 0) size: (302, 66) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UITableViewCellContentView (0x6385710): frame origin: (10, 1) size: (300, 63) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6379b10): frame origin: (10, 6) size: (277, 21) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6379eb0): frame origin: (10, 35) size: (227, 21) [tag=3] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIImageView (0x6147b70): frame origin: (10, 1) size: (300, 10) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   UITableViewCell (0x6386b60): frame origin: (0, 76) size: (320, 108) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIGroupTableViewCellBackground (0x63872c0): frame origin: (9, 0) size: (302, 108) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UITableViewCellContentView (0x6386d50): frame origin: (10, 1) size: (267, 105) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6387de0): frame origin: (10, 35) size: (227, 63) [tag=2] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6388350): frame origin: (10, 6) size: (235, 21) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIButton (0x6385c10): frame origin: (267, 1) size: (43, 105) [tag=0] UIControl : UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UIImageView (0x6386d80): frame origin: (7, 37) size: (29, 31) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIImageView (0x6387eb0): frame origin: (10, 1) size: (300, 10) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   UITableViewCell (0x63860a0): frame origin: (0, 10) size: (320, 46) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIGroupTableViewCellBackground (0x6386de0): frame origin: (9, 0) size: (302, 46) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UITableViewCellContentView (0x63882e0): frame origin: (10, 1) size: (267, 43) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UILabel (0x6385530): frame origin: (10, 0) size: (247, 43) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIButton (0x6385860): frame origin: (267, 1) size: (43, 43) [tag=0] UIControl : UIView : UIResponder : NSObject : 
.   .   .   .   .   .   .   UIImageView (0x6386000): frame origin: (7, 6) size: (29, 31) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   .   UIImageView (0x6386450): frame origin: (10, 1) size: (300, 10) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   UIImageView (0x615c020): frame origin: (0, 409) size: (320, 7) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   .   UIImageView (0x614a810): frame origin: (312, 1) size: (7, 144) [tag=0] UIView : UIResponder : NSObject : 
.   .   UINavigationBar (0x63192c0): frame origin: (0, 20) size: (320, 44) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   UILabel (0x6149360): frame origin: (62, 0) size: (200, 44) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   UILabel (0x61493d0): frame origin: (0, 19) size: (200, 20) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   .   UILabel (0x615c810): frame origin: (0, -1) size: (200, 24) [tag=0] UIView : UIResponder : NSObject : 
.   .   .   UINavigationItemButtonView (0x6349b80): frame origin: (5, 7) size: (49, 30) [tag=0] UINavigationItemView : UIView : UIResponder : NSObject : 
End of view hierarchy -----------------------------------

Notice above that my table view that I passed in is the first entry that is indented 4 levels in the above listing. This is because I used YES as the boolean parameter, which walks all the way to the top of the view hierarchy before dumping out all of the views.

Here is the code that generates it. First, the InspectView header file:

//
//  InspectView.h
//
 
#define objectString(anObject) [[anObject description] UTF8String]
 
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
 
@interface InspectView : NSObject 
{
}
 
+ (void)dumpViewToLog:(id)viewObj findParent:(BOOL)findTheParent;
+ (NSString *)dumpViewToString:(id)viewObj findParent:(BOOL)findTheParent;
+ (NSString *)dumpViewToString:(id)viewObj level:(int)level;
 
@end

And the implementation file:

//
//  InspectView.m
//
 
#import "InspectView.h"
 
#define THE_LOG NSLog
 
@implementation InspectView
 
+ (void)dumpViewToLog:(id)viewObj findParent:(BOOL)findTheParent
{
    THE_LOG(@"%@", [self dumpViewToString:viewObj findParent:findTheParent]);
}
 
+ (NSString *)dumpViewToString:(id)viewObj findParent:(BOOL)findTheParent 
{    
    NSString *s = @"\nInspect view hierarchy -----------------------------------" ;
 
    // go up to outtermost view.
    if (findTheParent)
    {
        s = [s stringByAppendingFormat:@"\nOriginal view is (0x%x)", viewObj];
 
        while ([viewObj superview]) 
        {
            viewObj = [viewObj superview];
        }
    }
 
    s = [s stringByAppendingString:[self dumpViewToString:viewObj level:0]];
    s = [s stringByAppendingString:@"\nEnd of view hierarchy -----------------------------------"];
    return s;
}
 
+ (NSString *) dumpViewToString:(id)viewObj level:(int)level 
{
    NSString *s = @"\n";
    // indent to show the current level
    for (int i = 0; i < level; i++) 
    {
        s = [s stringByAppendingString:@".   "];
    }
 
    s = [s stringByAppendingFormat:@"%@ (0x%x): frame origin: (%d, %d) size: (%d, %d) [tag=%d] ", 
         [[viewObj class] description], viewObj,
         (int) (((UIView*)viewObj).frame.origin.x), 
         (int) (((UIView*)viewObj).frame.origin.y),
         (int) (((UIView*)viewObj).frame.size.width),
         (int) (((UIView*)viewObj).frame.size.height),
         ((UIView*)viewObj).tag
         ];  // shows the hex address of input view.
    //  s = [s stringByAppendingFormat:@"%@ : ", [[viewObj class] description] ];
 
    id obj = [viewObj superclass];
 
    while (NULL != obj) 
    {
        s = [s stringByAppendingFormat:@"%@ : ", [[obj class] description]];
        obj = [obj superclass];
    }
 
    // recurse for all subviews
    for (UIView *sub in [viewObj subviews]) 
    {
        s = [s stringByAppendingString: [self dumpViewToString:sub level:(level + 1)]];
    }
 
    return s;
}
 
@end

If you combine today’s post with yesterday’s post (delayed block execution), you can do something like this at the end of the viewDidLoad method of your UITableViewController:

[self performBlock:^{ [InspectView dumpViewToLog:self.view findParent:NO]; } afterDelay:1.0f];
[self performBlock:^{ [InspectView dumpViewToLog:self.view findParent:NO]; } afterDelay:11.0f];

The result of this is that you will get a dump of your table view hierarchy after 1 second (this gives the table a chance to get drawn), the user will be able to work with the table view for another 10 seconds, and then another dump. This could help you diagnose any kind of issues you may be having with your table views or table view cells.

As usual, keep in mind that since this is code to be used for debugging purposes, this is not production quality code.

BTW, Happy Birthday to one of the all time great Leafs, Red Kelly.

Running a block after a delay

So I was looking for a way to easily run a block of Objective-C code after a set delay time. I found a few ways to do it, but one blog post I found encapsulated it pretty well. Here is the URL of that blog post:

Delayed Blocks in Objective-C (link redacted)

Using the NSObject category from the blog post, I can now run my block after a delay by using something like this:

[self performBlock:^{ [self myMethod]; } afterDelay:2.0f];

This will come in handy for my next blog post, which I will try to do over the weekend. (Hint: think of unrolling view hierarchies…)

BTW, Happy Birthday to Jack Lambert, one of the greatest Kent State alumni ever.

Batter vs. Pitcher app released

Well, I have finally released my Batter vs. Pitcher app that I have been working on for months now. The app is all about baseball statistics, so if you are a fan of baseball, please check it out:

Batter vs. Pitcher

BTW, Happy Birthday to John Kundla, former NBA coaching great. (I am not an NBA fan, but I could not find anyone I wanted to mention on the Wikipedia site for July 3, and his entry was the oldest on the births list that had not passed away.)