Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to use Obj-C with MacRuby/Rubymotion

Using Obj-C with MacRuby/Rubymotion

This little post aims to help you to translate Objective-C Blocks into Ruby blocks. Let's start by taking a look at few examples of iOS API call where blocks are used for animations and enumeration

Ruby Lambda Syntaxes:

Im Rubymotion and MacRuby you can use all the Ruby Lambda syntaxes that are:

block = lambda { |param|  ... }
block = lambda do |param|
	...
end

block = -> param { ... }
block = -> param do
	...
end

block = Proc.new{ |param| ... }
block = Proc.new do |name|
	....
end

block = proc { ... }
block = proc do |name|
  ...
end

####Objective-C Blocks with no arguments

[UIView animateWithDuration:0.2
     animations:^{view.alpha = 0.0;}]

this is how the Method looks like: __ + animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations__, this method takes two arguments duration and animations, where animations where animations is block (lambda) that takes no arguments

UIView.animateWithDuration(0.2, animations:-> { view.alpha = 0.0 })

####Objective-C Blocks with one argument

[UIView animateWithDuration:0.2
     animations:^{view.alpha = 0.0;}
     completion:^(BOOL finished){ [view removeFromSuperview]; }];

this is how the Method looks like: animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion, this method takes three arguments duration, animations and completion where animations and completion are blocks. the animations blocks does not take an argument, but completion does.

# we use the Ruby 1.9 Lambda sytax
UIView.animateWithDuration(0.2,
     animations:-> { view.alpha = 0.0 },
     completion:-> finished { view.removeFromSuperview })

Since we don't use the finished variable, we could also do this:

# we use the Ruby 1.9 Lambda sytax
UIView.animateWithDuration(0.2,
     animations:-> { view.alpha = 0.0 },
     completion:-> _ { view.removeFromSuperview })

####Objective-C Blocks with two arguments

NSSet *aSet = [NSSet setWithObjects: @"X", @"Y", @"Z", @"Pi", nil];
NSString *aString = @"z";
 
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
     if ([obj localizedCaseInsensitiveCompare:aString]==NSOrderedSame) {
          NSLog(@"Object Found: %@", obj);
          *stop = YES;
     }
} ];

The method enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block of NSSet is an enumeration method that takes a block with two arguments this is how it would look like in Ruby

the_set = NSSet.setWithObjects("X", "Y", "Z", "Pi", nil)
the_str = "z"

the_set.enumerateObjectsUsingBlock(lambda do |obj, stop|
  if obj.localizedCaseInsensitiveCompare(the_str) == NSOrderedSame
    NSLog("Object Found: %@", obj)
    stop.assign(true)
  end
end)

####Objective-C Blocks with three arguments

Using Block-Based Enumeration

The NSArray method (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block

NSArray *anArray = [NSArray arrayWithObjects:@"A", @"B", @"D", @"M", nil];
NSString *string = @"c";
 
[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
     if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
          NSLog(@"Object Found: %@ at index: %i",obj, index);
          *stop = YES;
     }
} ];

the Ruby Version

the_array = ["A", "B" ,"D", "C", "M"]
the_str = "c"

the_array.enumerateObjectsUsingBlock(-> obj, index, stop {
    if (obj.localizedCaseInsensitiveCompare(the_str) == NSOrderedSame)
        NSLog("Object Found: %@ at index: %@", obj, index)
		stop.assign(true)
	end
})

Now let's get crazy :-), you will be able to explain it yourself

strings = ["string 1", "String 21", "string 12", "String 11", "String 02"]

comparison_opts = NSCaseInsensitiveSearch | NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch
current_locale = NSLocale.currentLocale

result = strings.sortedArrayUsingComparator(lambda do |first, second|
  first_range = NSMakeRange(0, first.length)
  first.compare(second, options:comparison_opts, range:first_range, locale:current_locale)
end
)
NSLog("finderSortArray: %@", result)
@dentarg

This comment has been minimized.

Copy link

dentarg commented Feb 4, 2013

the_set = NSSet.setWithObjects("X", "Y", "Z", "Pi")

crashes for me.

the_set = NSSet.setWithObjects("X", "Y", "Z", "Pi", nil)

does not crash for me.

@seanlilmateus

This comment has been minimized.

Copy link
Owner Author

seanlilmateus commented Apr 2, 2013

@dentarg, where are you using it rubymotion or MacRuby?
it's actually working for but, it definitely better to use the nil termination.
thx

@alilalouch

This comment has been minimized.

Copy link

alilalouch commented Apr 8, 2013

In the first code snippet, you wrote lamda instead of lambda.

@seanlilmateus

This comment has been minimized.

Copy link
Owner Author

seanlilmateus commented Nov 1, 2013

Thanks @Aliezer, I never got a notification on your comment.
I corrected it...

@jclusso

This comment has been minimized.

Copy link

jclusso commented Sep 2, 2016

Update: Nevermind. The issue was that the method was wrong for the class. GPUImage has incorrect docs on their project :(

Can anyone help with this?

[stillCamera capturePhotoProcessedUpToFilter:filter withCompletionHandler:^(UIImage *processedImage, NSError *error){
    NSData *dataForJPEGFile = UIImageJPEGRepresentation(processedImage, 0.8);

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSError *error2 = nil;
    if (![dataForJPEGFile writeToFile:[documentsDirectory stringByAppendingPathComponent:@"FilteredPhoto.jpg"] options:NSAtomicWrite error:&error2])
    {
        return;
    }
}];

I tried this but I'm struggling because it doesn't work. Also the application just crashes with no errors. Note, my stillCamera is @camera

@camera.capturePhotoProcessedUpToFilter(
      @filter,
      withCompletionHandler: lambda do |processedImage, error|
        preview = PreviewPhotoController.alloc.initWithPhoto(processedImage)
        navigationController.pushViewController(preview, animated: false)
      end
    )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.