Hampton Lintorn Catlin

Macruby Pointers For NSError

I had to take some time today to figure this out, so I thought I’d share it here. It seems there is absolutely no documentation on this issue, so why not fix it myself?

All over Cocoa’s libraries, it uses the Objective-C pattern of passing in a reference to a variable and having it act as a sort of “second return variable”. In Obj-C it looks like this.

NSString *secondaryReturn;
        NSObject *primaryReturn = [object methodCall:&secondaryReturn];

At the end of this, both “primaryReturn” and “secondaryReturn” might have things stored in them. We see this pattern used mostly this way.

NSError *error;
        NSResult *result = [object riskyMethod:&error]
        if(error) {
          NSLog(@"That totally broke!")
        }

So, here… if the result fails, then error will store an NSError object. We’d hope that this would work.

result = object.riskyMethod(&error) #=> FAILLLLS

Nope! But, Macruby has given us an answer. Do this!

error = Pointer.new(:object)
        result = object.riskyMethod(error)
        if error[0]
          puts "That totally broke!" 
          puts error[0].class #=> NSError
        end

Ok, so first off, we introduce a class that macruby magically gives us. Pointer. When we initialize it, we tell it what kind of pointer it should be. There is a lot of documentation on what you can do with pointers in the specs for Macruby… but half of it I don’t understand and, moreover, I don’t need to. I always make an object pointer… and so should you! You can use the alternate form: Pointer.new(”@”) which is fancy Obj-C talk for an object. That, or we have a nice ruby symbol in the above example.

We setup the pointer and then pass it into the method call we are about to do. Once it completes, the way you access whatever is in the pointer is by using [0]. Don’t ask me why. I guess there are situations where error1 might point to something (the next thing in memory?) but, I haven’t hit one yet and its been many years since I was doing C seriously. But, when you call [0], you’ll get back either nil or an NSError. Viola! Problem solved. Here is a little pattern of how I’m using this along with an alert box.

def save!
          error = Pointer.new("@")
          was_successful = save(error)
          if !was_successful
            NSAlert.alertWithError(error[0]).runModal
          end
          was_successful
        end

This pops up an error message.

dna
Uploaded with Skitch!

Its not the sexiest thing in the world, but it sure does make a good start to things. Hope this helps you too!


Comments

Jan 16, 2011
@scott_to_s said...
YESSS! You totally helped. I couldn't figure out what an init method was asking for, even with the MacRuby docs in front of me. Thank you!
Mar 4, 2011
microspino said...
BRUTALLY useful thanks a lot!