Technology Musings

October 06, 2010

Platforms / When XCode Won't Symbolicate your Crash Log

On the iPhone, when you get crash logs, XCode is supposed to automatically look up symbols for you.  Sometimes, it doesn't.  Just had a crash report from the app store.  Loaded it up in the XCode organizer, and... nothing.  Zilch.  A lot of posts on the internet talked about "atos" but I just kept on getting the error:

atos cannot load symbols for the file

So, thankfully, I found this page on manually symbolicating your file.  Yay!

Basically, you can just run gdb on your archived package, set some configs, and then do p/a on the addresses and it will give you the proper symbols, files, and line numbers.  Magic!

/Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gdb/gdb-arm-apple-darwin YOURFILE.app
set print asm-demangle on
set print symbol-filename on
p/a 0x0whatever

Thanks so much to PiC Software for pointing this out.  And, of course, yay to the gcc and gdb developers who never get the credit that they should.

September 18, 2010

Platforms / Change in Video Playback in iOS 4 (MPMoviePlayerController)

JB

It seems that Apple has changed the way that it handles video playback in iOS 4.  In previous iPhone OS releases, you merely initialized the movie player instance and then hit play.  iOS 4 is slightly more complicated because it no longer presumes that all video playback will be fullscreen, or even that there will only be one video on the screen at a time.  So here is the code to get the old behavior: 

MPMoviePlayerController* thePlayer = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL URLWithString: trailerURL]];
thePlayer.scalingMode = MPMovieScalingModeAspectFill;
thePlayer.view.frame = self.view.bounds;
[self.view addSubview: thePlayer.view];[thePlayer setFullscreen: YES animated: YES];

Unfortunately, Apple still keeps its old documentation around. Here are the updated docs.

I ran into this when I was updating an app from 3.0 to 4.0. When you clicked on the button to play the video, rather than playing a video, nothing happened, and then a few seconds later only the audio would start playing. I had listed in my code the URL for the docs from Apple which I had used, and verified that it was correct - I had no idea that the document itself was out-of-date! It was quite a problem for me, and at first I thought it was a bug in my code. Later I learned that Apple updated their API, but not all their docs. Anyway, hope this helps someone.

July 13, 2010

Platforms / Comparing Research vs Practical Languages

JB

I recently ran across this excellent comparison between Standard ML and Objective Caml.  It is good, because it describes the different types of choices that are often made between languages used for research and those used for practical projects.

March 10, 2010

Platforms / Facebook FBJS problems on FireFox

JB

I've been banging my head against a wall for the past day trying to figure out various FBJS problems in facebook.  Turns out the problem was..... FireBug!  By simply turning Firebug off, (most of) my problems went away.  I have no idea what the issue is, but it took me forever to realize it because I always have FireBug on, and don't even realize it is there.  It's never been a problem before.  But, I noticed that one of my coworkers was using my app, with Firefox, with no problem, and I quickly realized that the problem was with FireBug.

There's still another issue with fb:js-string on profile widgets that's killing me, but hopefully that will be resolved soon.  I _think_ they changed how they were evaluating profile javascript, to make it more secure - but in doing so made all references to the variable created by fb:js-string out-of-scope.  Developing javascripty apps for facebook is truly painful.

January 27, 2010

Platforms / IE6 Retiring Soon!

JB

Looking at their lifecycle page, it looks like Microsoft will be retiring IE 6 this year!  For anyone who works in IT, this is certainly a cause for celebration.

January 16, 2010

Platforms / Forcing HTTP Basic Authentication on the iPhone

JB

Here's my setup.  I have a RESTful Rails app.  Going to http://whatever.com/contacts gives the search screen for the contacts.  Going to http://whatever.com/contacts.xml gives the full list of contacts as an XML file.  For normal users, I use cookie-based authentication.  However, I also allow, for API users, HTTP basic authentication.  There is no access difference between the two.  However, this is a problem for the iPhone, because, although NSURL supports usernames and passwords, it will not present them for authentication without being challenged!  This is somewhat understandable because it doesn't know what authentication mechanism is being used (basic or digest).  However, it is EXTREMELY annoying to program for.

So, after spending about 2 hours digging through stuff, here is what I found out.

First of all, Basic authentication relies upon Base64 encoding, which isn't available on the iPhone.  Thankfully, someone posted public-domain Objective-C iPhone code for this here and someone else gave an almost-working-but-not-quite version of the request code here.  The Base64 code left out some things (like the class wrapper and header file), and the request code assumed a Base64 method existed which didn't.  In any case, here is the Base64 header file, Base64.h:

#import <Foundation/Foundation.h>


@interface Base64 : NSObject {
}
+ (void) initialize;
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length;
+ (NSString*) encode:(NSData*) rawBytes;
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength;
+ (NSData*) decode:(NSString*) string;

@end

Here is the body of the code, Base64.m:

#import "Base64.h"


@implementation Base64

/* Copied from http://www.cocoadev.com/index.pl?BaseSixtyFour (cyrus.najmabadi@gmail.com) */

#define ArrayLength(x) (sizeof(x)/sizeof(*(x)))

static char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char decodingTable[128];

+ (void) initialize {
if (self == [Base64 class]) {
memset(decodingTable, 0, ArrayLength(decodingTable));
for (NSInteger i = 0; i < ArrayLength(encodingTable); i++) {
decodingTable[encodingTable[i]] = i;
}
}
}


+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;

for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;

if (j < length) {
value |= (0xFF & input[j]);
}
}

NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}

return [[[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding] autorelease];
}


+ (NSString*) encode:(NSData*) rawBytes {
return [self encode:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}


+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength {
if ((string == NULL) || (inputLength % 4 != 0)) {
return nil;
}

while (inputLength > 0 && string[inputLength - 1] == '=') {
inputLength--;
}

NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t* output = data.mutableBytes;

NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
while (inputPoint < inputLength) {
char i0 = string[inputPoint++];
char i1 = string[inputPoint++];
char i2 = inputPoint < inputLength ? string[inputPoint++] : 'A'; /* 'A' will decode to \0 */
char i3 = inputPoint < inputLength ? string[inputPoint++] : 'A';

output[outputPoint++] = (decodingTable[i0] << 2) | (decodingTable[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i1] & 0xf) << 4) | (decodingTable[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i2] & 0x3) << 6) | decodingTable[i3];
}
}

return data;
}


+ (NSData*) decode:(NSString*) string {
return [self decode:[string cStringUsingEncoding:NSASCIIStringEncoding] length:string.length];
}


@end

Okay, so now how do we make the request?  It's pretty evil, but if you wrap it in a function it's not too bad.  Don't forget to import Base64.h!  Anyway, here is the code:

+ (NSData *) loadDataFromURLForcingBasicAuth:(NSURL *url) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *authString = [Base64 encode:[[NSString stringWithFormat:@"%@:%@",[url user], [url password]] dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:[NSString stringWithFormat:@"Basic %@", authString] forHTTPHeaderField:@"Authorization"];
return [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
}

Ugly, ain't it?  You can use this with asynchronous connections as well, or extend it to handle the responses/errors from sendSynchronchronousRequest, but that is an exercise for the reader.

 

 

 

 

 

 

November 11, 2009

Platforms / Debugging EXC_BAD_ACCESS on the iPhone

JB

I've been working on my first real iPhone app.  It's a very interesting way of coding.  Objective-C is an interesting language.  It seems to shoot for the middle ground between something out-of-control like C++, and something so-object-oriented-it-hurts like Java.  Personally, I like Ruby best, but that's neither here nor there.

Memory management on the iPhone is a tough cookie for someone who has not done Objective-C development before.  If you are new to the iPhone, the first thing you should do is read the memory management contract for Cocoa, as well as the links that link out from there.

I was having a problem getting EXC_BAD_ACCESS.  I finally used breakpoints to find where the problem was occurring, and it was an NSArray that was causing it.

I did a google search, and found this really cool method for getting a little more information about objects which have been released before they were accessed.

Eventually, I found out that the problem came from the fact that [NSArray arrayWithObjects:], because it doesn't have "init" or "copy" or "alloc" in the message name for object creation, autoreleases the object when it gives it to me!  Therefore, as soon as the present event was done, it trashed the object.  If you want to keep an object that has been autoreleased, you have to send it a retain message.

Doing the retain fixed my problem.  Yay!

July 05, 2009

Platforms / Migrating to Phusion Passenger

JB

Spent the evening migrating one of my Ruby on Rails servers to Phusion Passenger.  It was a nice upgrade, but not the trouble-free upgrade they promise.  Here were the gotchas that I ran into:

  1. Remember to install all of the gems into your new enterprise ruby that were on your regular ruby.  This one is pretty obvious, but its easy to miss some
  2. Passenger preloads your application.  This means that if there were models that you never used (and thus never got loaded into Rails before), Passenger will load them for you, and if they are broken, your app will not start.  This also affected gem loading, as there was one gem which was loaded by a file that was unused, and therefore I didn't have it installed.  But Passenger required that I install the gem.
  3. Passenger basically works by default as a SetUID program.  It looks like whatever user owns the application is the user that Passenger will run it as.  This can cause all sorts of problems.  It can cause problems accessing log files and session files.  When I finally got my gem issues sorted out, I kept getting 500 errors and I found the following in my log file: file /tmp/ruby_sess.97c076be86e7dd90 not readable - This was because it was running as my development user rather than as Apache.  I had to use BOTH of the directives "PassengerUserSwitching off" and "PassengerDefaultUser apache" to get it to work.  
  4. Then I had to find and fix all of the badly-created permissions that had accrued while it was running as the wrong user
If I have any additional problems, I'll post them here.

August 20, 2008

Platforms / Go Gobo!

JB

GoboLinux is trying new things in the filesystem hierarchy department (details here)  i think this is fantastic!  Linux definitely needs to do this, plus it needs to adopt OSX's bundle concept.

It looks like there is already some work in this area, but it surely needs to be extended and accepted by the Linux community.

June 05, 2008

Platforms / Why You Should Bet on Apple and Ruby on Rails

JB

I just had a few friends come back from RailsConf 2008.  1,800 developers showed up.  Wow!

After talking with them, I have the following to offer you as to why you should bet on Ruby-on-Rails:

  1. Ruby-on-Rails is a great platform and just keeps getting better
  2. Sun recognizes the value of Ruby and Rails and is working hard to integrate Ruby and Rails into their Java systems, by making Ruby run on Java, making Rails apps deployable on J2EE containers, and by extending Netbeans to support Java development
  3. Microsoft recognizes the value of Ruby and Rails, and is shifting their entire developer strategy to compensate.  This is the most telling part.  Microsoft has done the following:
    1. They are building a dynamic-language version of their CLR
    2. They are porting Ruby and Rails to their CLR, with their primary goal being compatibility with existing Ruby and Rails (when was the last time you heard Microsoft put compatibility as their primary development goal?)!
    3. They have started developing tools geared at dynamic language support
    4. They have completely re-engineered the ASP.NET libraries in order to adopt a more Rails-like MVC model

The web development world is in a sudden shift towards Rails, simply because it is awesome as a development environment!

So, I also mentioned Apple in my subject.  To understand why I think Apple will continue its path towards domination, keep in mind the following:

  1. Ruby runs on every platform
  2. Rails runs on every platform
  3. Development tools exist for Ruby and Rails on every platfor

My friends who went to RailsConf were stunned by the fact that, almost without exception, every developer at RailsConf had a MacBook Pro.  Think about that.  Apple is capturing the hearts and minds of the upcoming generation of developers.  Even some of my friends who do Windows development, do their development on a Mac running a Windows virtual machine!

Take note of the following facts:

  1. Firefox users are bordering on 20% market share
  2. Microsoft just finished crossing every one of its users with Vista, and the users are revolting by switching to either Mac or back to XP
  3. Mac continues to have the earned reputation of hassle-free "just-working"
  4. Apple has capture the hearts and imaginations  of all developers - from Linux to Mac to even Windows developers.  I'm a Linux developer who switched to Mac.  Why?  Because it appeals both to us old UNIX junkies as well as to the slick and flash artist types.
Be watching Apple.  They are not stopping any time soon.