the codemonky

ramblings, musing and code snippets from shawn veader
Aug 31
Permalink

Clearing Cached Credentials on the iPhone

My latest iPhone project hits an API to fetch data. All was well and good until I began to test with the account I was going to turn over to the Apple review folks. Turns out, switching login credentials had no effect. After digging in, I realized I had the cache policy for the credentials set to:


NSURLCredentialPersistenceForSession

So I began to hunt for a mechanism to clear this cached credential so the next request would hit the NSURLConnection delegate:


- (void)connection:didReceiveAuthenticationChallenge:

I started with:


[[NSURLCache sharedURLCache] removeAllCachedResponses];

But this didn’t help. So I moved onto:


[NSURLCredentialStorage sharedCredentialStorage]

This lead me down trying to clear all the credentials in the storage; however, much to my surprise, this did nothing either. Hmm… Well, thinking back to browser land, I decided to hunt down any cookies that might be stashed somewhere. This lead me to:


[NSHTTPCookieStorage sharedHTTPCookieStorage]

After clearing out all the cookies for the domain I was hitting, I finally got the request to prompt for validation credentials again. I’m pretty sure all parts of this aren’t needed, but I’m being overly paranoid at this point. The resulting code can be found at this gist

Jul 30
Permalink

My dates leak memory

Doing some iPhone hacking recently and poking around the leaks instrument. Noticed a call to NSDate causing some leaking. Getting to the meat of it was this code block:


NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzzz"];
NSDate *dateTime = [formatter dateFromString:newTimeString];

The leaks instrument pointed to the call to -dateFromString: on the NSDateFormatter doing the leak.

… <blink> …

On the core class? Yup, did some Googling and found some other folks with the same problem. Here was the best answer I found:
http://thegothicparty.com/dev/article/nsdateformatter-memory-leak/

Evidently, the time zone piece of the format string was leaking memory.

Turns out I had another bug in my time formatting code so I ended up switching the “zzzz” for “Z” and my memory leak and bug went away.

So if you are converting dates with timezones, see if you can use the “Z” format not the “z”, even if you have to munge your string a bit to get that.

For more information on the formatting strings:
http://unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns

Apr 26
Permalink

bummed i missed worldwide pinhole camera day yesterday (on my birthday, no less). maybe photojojo will give me a pinhole so i can fix that problem.

i really dig the wide aspect ratio of this guys work. above photo from aranjuez chou

see what i’m talking about here

Mar 19
Permalink
photojojo:

Photojojo is running a CRAZY experiment for the next 3 hours!
Reblog this post before 4pm EDT on 3/19 (1 pm PDT) and the amazing Instax Instant Camera price goes down 10 cents for EVERY REBLOG!
Reblog, check the price &amp; snap one up before they’re gone. Price goes back to normal @ 4pm or when they run out!
p.s. The lowest possible price is zero, no negative funny business, mister. And you should follow Photojojo on Tumblr cuz it’s awesome!
UPDATE: We’re running out of cameras! The response is crrrrrazy. There’s no way we’ll have stock in an hour.

photojojo:

Photojojo is running a CRAZY experiment for the next 3 hours!

Reblog this post before 4pm EDT on 3/19 (1 pm PDT) and the amazing Instax Instant Camera price goes down 10 cents for EVERY REBLOG!

Reblog, check the price & snap one up before they’re gone. Price goes back to normal @ 4pm or when they run out!

p.s. The lowest possible price is zero, no negative funny business, mister. And you should follow Photojojo on Tumblr cuz it’s awesome!

UPDATE: We’re running out of cameras! The response is crrrrrazy. There’s no way we’ll have stock in an hour.

Mar 04
Permalink

iPhone Dev : Determining Text Height

OK, so you’re developing your application and programmatically laying out your UILabel. You want to know the height the label will ultimately be, so you can set the frame accordingly. You poke around and find the following method buried in NSString.


sizeWithFont:forWidth:lineBreakMode:

Thinking you’ve struck gold, you proceed. Once you run your app you realize this method will never give you a height for more than one line. This has to be a bug, you think to yourself.

http://openradar.appspot.com/radar?id=74427

Nope! Apple says it works as intended. This seems like a waste because you can get the same information out of UIFont. Sigh.

You end up having to go with NSString’s sizeWithFont:constrainedToSize:lineBreakMode: method and using a constraint with unlimited height. Here’s the full scoop.


// determine your width before and put it here
CGSize constrainedSize = CGSizeMake(width, MAXFLOAT);
UIFont *textFont = [UIFont systemFontOfSize:13.0f];
NSString *text = @"Some very long string goes here...";
CGSize textSize = [text sizeWithFont:textFont 
                   constrainedToSize:constrainedSize 
                       lineBreakMode:UILineBreakModeWordWrap];

Hopefully some day Apple will fix that first method to do the sane thing, but don’t hold your breath.

Feb 05
Permalink

Running the iPhone 3.2 Beta… First Gotchas

I installed the 3.2 beta the other day to play with the new iPad simulator. (Neat stuff… more on that later.) But I tried working on one of my many half-completed iPhone apps the other night and ran into a few interesting problems.

The first problem I encountered was that the credentials in my app were not saving to the user defaults. I scratched my head a few times with this but did get some good testing out of it.

The second problem was the one that eventually led me to hitting Google in search of answers. After getting past some bugs I uncovered by not having user credentials, my app tried to load a standard table view. This table view has a custom cell loaded from a NIB. When the app tried to load this NIB, I was greeted with this wonderful message in the console.

uncaught exception ‘NSInvalidUnarchiveOperationException’, reason: ‘*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (UITableViewCellContentView)’

A few Google searches later and I found this response over on StackOverflow. However, I found it hard to believe that all of a sudden I needed to declare a class that was supposed to be built into the framework. I then started poking at XCode and the simulator and noticed something strange….

I had opened my project from the console (yes, I’m *that* guy) with the “open” command as I always do. Unbeknownst to me this opened the newer XCode out of the alternate install. This turned out to be the root of all my problems. I opened /Developer/Applications/XCode.app and BOOM everything started working again.

So if you’re running dual development environments, watch out!

Jan 07
Permalink

Obj-C Oddities

I never seem to find enough time to be in Obj-C land long enough to develop muscle memory so there are things that consistently get me. NSDictionary creation is backwards:

NSDictionary *stuff = 
[NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", 
                                           @"value2", @"key2", nil];
In Ruby-land (where I’ve been for quite some time) it would be:
stuff = { :key1 => "value1", :key2 => "value2" }
Almost forgot! I also almost always forget the nil at the end of an NSDictionary or NSArray declaration. For instance:
NSArray *myList = [NSArray arrayWithObjects: @"foo", @"bar", @"baz", nil];
I continually forget that trailing nil, but it should be obvious since C is under the covers after all.

Jul 28
Permalink

Zombies are your friend!

No, they’re not here to eat your brain this time. They are here to save it.

So you’re happily coding along in Obj-C and developing the next big iPhone app. You build and run in the simulator only to see it crash and give EXC_BAD_ACCESS in the console. You then spend a few minutes to a few hours (depending on how persistent you are) debugging and trying to chase down the problem (which, by the way, is usually trying to send a message to a released object). Compound this by having a multithreaded application (you are using threads, right?) and you can start to feel the frustration building.

Now envision some zombies coming to help. Yes, zombies.

Well… not real zombies of course.


Objective-C was kind enough to include an awesome environment variable you can set that will leave around a dummy object for everything that is released so you can see where that EXC_BAD_ACCESS is coming from.

The environment variable is NSZombieEnabled. Edit the executable options in XCode and create a new environment variable named NSZombieEnabled and set the value to YES. It should look like this:

Now build and run and see what you get. Enjoy!

Jun 24
Permalink

Animated GIFs and UIImageViews

OK, so while building an iPhone app last night I ran into a little snag. We are using an animated GIF on the loading screen to allow the user to see something pretty while they wait.

Being naive, I assumed the UIImageView would display the animated GIF. Well… I was partially right. It does display the GIF but only the first frame.

Then the Google hunt began…

After some searching, I had found that you can set the animatedImages property of a UIImageView to a NSArray that contains each frame of the animated GIF and then call the startAnimating method to “play” it.

OK, great…. now how do I get the frames out? After more Googling I just tried Preview.app on a wild hair. I’m glad to report that it shows the animated GIF but in the drawer of the app, it also has each frame. Simply drag each of these out and boom! you’re set.

Now for the code sample.

UIImage *frame0 = [UIImage imageNamed:@"frame0.png"];
// ... more frames here ...
UIImage *frameN = [UIImage imageNamed:@"frameN.png"];

// animatedGif is a UIImageView initialized in your NIB or elsewhere.
animatedGif.animatedImages = [[NSArray alloc] initWithObjects:frame0
                                                              ....
                                                              frameN,
                                                              nil];
[animatedGif startAnimating];

There are a few other things you can play with like the animatedDuration and animatedRepeatCount properties. But you can figure those out.

And a link to the UIImageView documentation for completeness… UIImageView

Jun 16
Permalink

Must haves for Safari

So I’m back on Safari, for the moment, (no offense Firefox) and I just wanted to pass along two plugins that you must install.


Click-to-Flash

http://github.com/rentzsch/clicktoflash/tree/master

This replaces any flash on a website with a little logo that says “Flash”. If you actually want to see the flash you just click it and it loads. Works very well to keep the browser from chewing up all your computing resources running Flash. (Adobe: why is Flash so horrible?)


AdBlock

http://burgersoftware.com/en/safariadblock

Recent addition for me but blocks ad content for a more pleasant browsing experience.